你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F030的硬件SPI从模式,从机应答时丢失首个字节?

[复制链接]
Dylan疾风闪电 提问时间:2015-1-5 20:36 /
如题,主机发送{0,0,0,0},想要得到的从机应答{0x00,0x70,0x53,0xb0};实际获取的应答为{0x70,0x53,0xb0,0x00}。

中断程序如下:

  1. uint32_t spi_TxBuff = 0x00000000;

  2. uint32_t DataRegs[10];
  3. #define OFFSET_0                        24
  4. uint8_t offsetbits = OFFSET_0;

  5. uint8_t rw_Flag;//0x00:read,0x80:write,=data & 0x80;
  6. uint8_t reg_Address;//=data & 0x7F;

  7. void SPI2_IRQHandler(void)
  8. {
  9.         uint8_t data;
  10.        
  11.         if (SPI2->SR & 0x1)
  12.         {
  13.                 data = SPI_ReceiveData8(SPI2);
  14.                
  15.                 rw_Flag = data & 0x80;
  16.                 reg_Address = data & 0x7F;
  17.                
  18.                 if (rw_Flag != 0x00)
  19.                 {
  20.                         //write to regs
  21.                        
  22.                         //SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
  23.                 }
  24.                 else
  25.                 {
  26.                         //read from regs       
  27.                         if (reg_Address < 10)
  28.                         {
  29.                                 if (offsetbits == OFFSET_0)
  30.                                 {
  31.                                         spi_TxBuff = DataRegs[reg_Address];
  32.                                 }
  33.                         }
  34.                         else
  35.                         {
  36.                                 spi_TxBuff = 0x00FFFFFF;
  37.                         }
  38.                 }
  39.         }
  40.        
  41.         if (SPI2->SR & 0x2)
  42.         {
  43.                 SPI_SendData8(SPI2, (0xFF & (spi_TxBuff >> offsetbits)));
  44.                
  45.                 if (offsetbits >= 8)
  46.                 {
  47.                         offsetbits -= 8;
  48.                 }
  49.                 else
  50.                 {
  51.                         offsetbits = OFFSET_0;
  52.                 }
  53.         }
  54. }

  55. void EXTI4_15_IRQHandler(void)
  56. {
  57.         EXTI->PR ^= (uint16_t)~EXTI_Line11;

  58.         offsetbits = OFFSET_0;
  59. }
复制代码


收藏 评论15 发布时间:2015-1-5 20:36

举报

15个回答
Dylan疾风闪电 回答时间:2015-1-5 20:42:42
本帖最后由 Dylan疾风闪电 于 2015-1-5 20:44 编辑

SPI的主/从的初始化代码:
  1. void connectSPI1ToExt(uint16_t BaudRatePCLKDiv, uint16_t CPOL, uint16_t CPHA_Edge)
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         SPI_InitTypeDef  SPI_InitStructure;

  5.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  6.         //SPIx_SCK 主模式 推挽复用输出
  7.         //SPIx_MOSI 全双工模式/主模式 推挽复用输出
  8.         //SPIx_MISO 全双工模式/主模式 浮空输入或带上拉输入
  9.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  10.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  11.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  13.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X2_CLK);
  14.         GPIO_Init(SPLIT_DEFINE_PORT(X2_CLK), &GPIO_InitStructure);
  15.         SetAF_SPI1_SCK;
  16.        
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  18.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  19.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  20.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  21.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X2_SDI);
  22.         GPIO_Init(SPLIT_DEFINE_PORT(X2_SDI), &GPIO_InitStructure);
  23.         SetAF_SPI1_MOSI;

  24.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  25.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  26.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  27.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  28.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X2_SDO);
  29.         GPIO_Init(SPLIT_DEFINE_PORT(X2_SDO), &GPIO_InitStructure);
  30.         SetAF_SPI1_MISO;

  31.         //
  32.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  33.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE);
  34.         RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE);

  35.         SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  36.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  37.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  38.         SPI_InitStructure.SPI_CPOL = CPOL;
  39.         SPI_InitStructure.SPI_CPHA = CPHA_Edge;
  40.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  41.         SPI_InitStructure.SPI_BaudRatePrescaler = BaudRatePCLKDiv;
  42.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  43.         SPI_InitStructure.SPI_CRCPolynomial = 7;
  44.         SPI_Init(SPI1, &SPI_InitStructure);
  45.         SPI_CalculateCRC(SPI1,DISABLE);

  46.         SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);

  47.         SPI_Cmd(SPI1, ENABLE);
  48. }

  49. void connectSPI2SlaveToExt(uint16_t BaudRatePCLKDiv, uint16_t CPOL, uint16_t CPHA_Edge)
  50. {
  51.         GPIO_InitTypeDef GPIO_InitStructure;

  52.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

  53.         //SPIx_SCK 从模式 浮空输入
  54.         //SPIx_MOSI 全双工模式/从模式 浮空输入或带上拉输入
  55.         //SPIx_MISO 全双工模式/从模式 推挽复用输出
  56.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  57.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  58.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  59.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  60.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_CLK_S);
  61.         GPIO_Init(SPLIT_DEFINE_PORT(X3_CLK_S), &GPIO_InitStructure);
  62.         SetAF_SPI2_SCK;

  63.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  64.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  65.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  66.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  67.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_SDI_S);
  68.         GPIO_Init(SPLIT_DEFINE_PORT(X3_SDI_S), &GPIO_InitStructure);
  69.         SetAF_SPI2_MOSI;

  70.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  71.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  72.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  73.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  74.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_SDO_S);
  75.         GPIO_Init(SPLIT_DEFINE_PORT(X3_SDO_S), &GPIO_InitStructure);
  76.         SetAF_SPI2_MISO;
  77.        
  78.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  79.         GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  80.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  81.         GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  82.         GPIO_InitStructure.GPIO_Pin = SPLIT_DEFINE_PIN(X3_CS_S);
  83.         GPIO_Init(SPLIT_DEFINE_PORT(X3_CS_S), &GPIO_InitStructure);
  84.         SetAF_SPI2_NSS;

  85.         //寄存器操作
  86.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
  87.         RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, ENABLE);
  88.         RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2, DISABLE);

  89.         /*---------------------------- SPIx CR1 Configuration ------------------------
  90.          *
  91.          * [15]BIDIMode(双向数据模式使能) = 0 :选择2线的单向数据模式(1:选择单线双向数据模式)。
  92.          * [14]BIDIOE(双向模式输出使能) = 0 :输出禁止,只收模式(1:输出使能,只发模式)。
  93.          * *注* BIDIOE和BIDIMode决定了通讯的“双线单向模式”、“单线双向模式”和“单线单向模式”。
  94.          * [13]CRCEN(硬件CRC使能) = 0 :禁用CRC计算(1:CRC计算使能)。
  95.          * [12]CRCNEXT(下一个发送CRC) = 0 :下个发送的值来自发送缓冲器(1:下个发送的值来自CRC寄存器).
  96.          * [11]CRCL(CRC的数据长度) = x (0:8位CRC长度)(1:16位CRC长度).
  97.          * [10]RxONLY = 0 :全双工(1:只收模式)。
  98.          * [9]SSM(软件从机管理) = 0 :禁止软件从设备管理(1:启用软件从设备管理,NSS引脚的电平由SSI位决定)。
  99.          * [8]SSI(内部从设备选择) = x 决定了NSS引脚的电平。
  100.          * [7]LSBFirst(帧格式) = 0 :先发送MSB(1:先发送LSB)。
  101.          * [6]SPE(SPI使能) = 0 :禁止SPI设备(1:开启SPI设备)。
  102.          * [5:3]BR(波特率控制) = value (通信速率为{fPCLK/(2^[value+1)]})。
  103.          * [2]MSTR(主设备选择) = 0 :配置为从设备(1:配置为主设备)。
  104.          * [1]CPOL(时钟极性) = value (0:空闲状态下SCK保持低电平)(1:空闲状态SCK保持高电平)。
  105.          * [0]CPHA(时钟相位) = value (0:第一个时钟边沿开始数据采样)(1:第二个时钟边沿开始数据采样)。
  106.          *---------------------------------------------------------------------------*/

  107.         SPI2->CR1 &= 0x0000;
  108.         SPI2->CR1 |= (uint16_t)(BaudRatePCLKDiv | CPOL | CPHA_Edge);

  109.         /*---------------------------- SPIx CR2 Configuration ------------------------
  110.          *
  111.          * [11:8]DS(数据长度) = 0111b :8位(0011b~1111b:4位~16位数据长度)。
  112.          *---------------------------------------------------------------------------*/
  113.         SPI2->CR2 &= 0xF0FF;
  114.         SPI2->CR2 |= 0x0700;
  115.   
  116.         /*---------------------------- SPIx CRCPOLY Configuration --------------------
  117.          *
  118.          * [15:0]CRCPOLY(数据长度) = 0x0007 :默认的复位值是0x0007。(复位过后可忽略)
  119.          *---------------------------------------------------------------------------*/
  120.         //SPI2->CRCPR = 0x0007;

  121.         /*---------------------------- Activate the SPI mode -------------------------
  122.          *
  123.          * [11]I2SMODE(I2S模式选择) = 0 :选择SPI模式(选择I2S模式)。
  124.          *---------------------------------------------------------------------------*/
  125.         SPI2->I2SCFGR &= 0xF7FF;       

  126.         SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF);

  127.         SPI_Cmd(SPI2, ENABLE);
  128. }
复制代码


Dylan疾风闪电 回答时间:2015-1-5 20:52:29
主循环部分代码:
  1. uint8_t temp[20];
  2. ......

  3. int main()
  4. {
  5.         NVIC_InitTypeDef NVIC_InitStructure;

  6.         ......

  7.         connectSPI1ToExt(SPI_BaudRatePrescaler_32, SPI_CPOL_Low, SPI_CPHA_1Edge);

  8.         connectSPI2SlaveToExt(SPI_BaudRatePrescaler_32, SPI_CPOL_Low, SPI_CPHA_1Edge);
  9.         SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);       
  10.         SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);

  11.         //Interrupts
  12.         NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
  13.         NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
  14.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  15.         NVIC_Init(&NVIC_InitStructure);

  16.         NVIC_InitStructure.NVIC_IRQChannel = EXTI4_15_IRQn;
  17.         NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
  18.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  19.         NVIC_Init(&NVIC_InitStructure);

  20.         while(1)
  21.         {
  22.                 DELAY_MS(500);               
  23.                 SPI1_SS_Low;
  24.                 DELAY_MS(10);
  25.                        
  26.                 for(int i=0; i<4; i++)
  27.                 {
  28.                         temp[i] = 0;
  29.                                
  30.                         while (!(SPI1->SR & 0x2));               
  31.                         SPI_SendData8(SPI1, 0x00);
  32.                        
  33.                         while (!(SPI1->SR & 0x1));               
  34.                         temp[i] = SPI_ReceiveData8(SPI1);
  35.                 }
  36.                        
  37.                 DELAY_MS(10);
  38.                 SPI1_SS_High;;
  39.                 DELAY_MS(500);
  40.         }
  41. }
复制代码
Dylan疾风闪电 回答时间:2015-1-5 20:59:18
请各位帮忙看一下,中断处理函数是不是存在什么问题?
因为从设备启用了硬件NSS,所以在片选为高的情况下,硬件应答是0xFF;同时在片选上升沿通过EXTI中断复位偏移量(offsetbits)。
----------------------------------------------------------------------------------------------------
收到数据0x00后,依次发送spi_TxBuff的【31:24】【23:16】【15:8】【7:0】。
Dylan疾风闪电 回答时间:2015-1-12 16:43:45
自己顶一下,哪位高工来看一下,这个问题怎么解决?
6874577 回答时间:2015-1-13 12:48:25
这个问题怎么解决?
Dylan疾风闪电 回答时间:2015-1-13 16:40:21
6874577 发表于 2015-1-13 12:48
这个问题怎么解决?

我就是想知道啊!不知道程序哪边有问题,重点怀疑是中断函数中的处理机制。
废鱼 回答时间:2015-1-13 17:40:47
在SPI发送中加断点,看一下发送的时候的spi_TxBuff数据是多少,另外看一下offsetbits值是多少。
Dylan疾风闪电 回答时间:2015-1-13 21:54:31
spi_TxBuff=0x007053b0;
offsetbits = 24;
mlxy123xy 回答时间:2015-1-14 00:16:39
从机应答丢失首字节,你试试从机响应的首字节加点延迟。
废鱼 回答时间:2015-1-14 09:26:35
SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);
这个在收到数据以后再开启试试吧。可能是先发送了一次,导致你的程序没有收到最先发送的。这个开启以后,只要是发送寄存器为空就会进入中断。
废鱼 回答时间:2015-1-14 09:27:04
可以仿真在发送之前是不是先进入了一次中断。
ludongshalimin 回答时间:2015-1-14 10:47:27
1:加延时
2:你看看你的代码是不是把0x00给滤掉了
行者person 回答时间:2015-7-10 17:25:31
我也出现过这种问题,后来将CPHA设置为1后好了。
可以换种模式试试。
Dylan疾风闪电 回答时间:2015-7-23 10:54:33
谢谢大家,换下采样时钟边沿看看(14楼的建议)
12下一页
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版