nRF52832的SPIM收发1Byte数据时长度出错和解决方法

1.问题描述

        用nRF52832(SDK:Nordic SDK 17.0.2.)的SPIM和w5500通信时,发现网口初始化无法通过,用示波器分别捅了一下片选、时钟、MOSI、MISO,发现时钟居然是1byte和2byte交替出现的,MOSI数据也出错了:

         蓝色是时钟,绿色是片选,黄色是MOSI。每当出现2byte的数据时,MOSI后面凭空跟了个0xff在后面,但是我的SPIM收发函数是1byte的:

/*****************************************************************************
** 描  述:写入、读出一个字节
** 参  数:Dat:待写入的数据
** 返回值:读出的字节
******************************************************************************/
uint8_t Spi_WriteReadOneByte(uint8_t Dat)
{
    uint8_t len = 1;
	
    spi_tx_buf[0] = Dat;
	spi_xfer_done = false;
	APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
    while(!spi_xfer_done);
	return (spi_rx_buf[0]);
}

 2.原因查找

        经检查不是函数的问题,于是去翻阅了一下开发指南,找到了这样两段话:

 

        符合我遇见的现象,于是去代码中查看了SPI的配置:

        orc确实是0xff,于是把orc随意改成一个其他的值,再用示波器测量,发现MOSI发出的数据也相应发生了变化。但是我明明只调用了1byte数据收发函数,TXD.MAXCNT和RXD.MAXCNT都是1。

        去Nordic论坛查找,发现有人和我出现了一样的问题,在官网上有一个纠错手册《Errata》,上面有方法解决这个问题(没想到竟是芯片自身的问题):

 文件下载:Nordic Semiconductor Infocenter

 3.问题解决

        根据纠错手册提供的解决方法是:使用52832的PPI,将SPIM的CLK电平翻转作为事件端点,将SPIM关闭作为任务端点。每当CLK发生电平变化时,便会关闭SPIM。但是52832的SPIM无法在1byte数据没有传输完成时关闭,SPIM会等到1byte数据传输完成之后再关闭,进而解决了多余字节的问题。手册提供的函数如下:

/**
 * @brief Work-around for transmitting 1 byte with SPIM.
 *
 * @param spim: The SPIM instance that is in use.
 * @param ppi_channel: An unused PPI channel that will be used by the workaround.
 * @param gpiote_channel: An unused GPIOTE channel that will be used by the workaround.
 * 
 * @warning Must not be used when transmitting multiple bytes.
 * @warning After this workaround is used, the user must reset the PPI channel and the
 GPIOTE channel before attempting to transmit multiple bytes.
 */
void setup_workaround_for_ftpan_58(NRF_SPIM_Type * spim, uint32_t ppi_channel, uint32_t gpiote_channel)
{
	 // Create an event when SCK toggles.
	 NRF_GPIOTE->CONFIG[gpiote_channel] = (
	 GPIOTE_CONFIG_MODE_Event <<
	 GPIOTE_CONFIG_MODE_Pos
	 ) | (
	 spim->PSEL.SCK <<
	 GPIOTE_CONFIG_PSEL_Pos
	 ) | (
	 GPIOTE_CONFIG_POLARITY_Toggle <<
	 GPIOTE_CONFIG_POLARITY_Pos
	 );
	 // Stop the spim instance when SCK toggles.
	 NRF_PPI->CH[ppi_channel].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[gpiote_channel];
	 NRF_PPI->CH[ppi_channel].TEP = (uint32_t)&spim->TASKS_STOP;
	 NRF_PPI->CHENSET = 1U << ppi_channel;
	 // The spim instance cannot be stopped mid-byte, so it will finish
	 // transmitting the first byte and then stop. Effectively ensuring
	 // that only 1 byte is transmitted.
}

        这样调用即可:

void spi_ppi_set(void)
{
	setup_workaround_for_ftpan_58(NRF_SPIM0, 6, 0);
}

        注意点:1.一旦建立起这个PPI通道,就只能单字节地收发数据了,若是想要多字节收发,需要关闭该通道;

                        2.需要使用硬件控制CS电平;

                        3.需要将orc改成0x00,不然数据还是会出错。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值