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

要被STM32的SPI从机DMA玩死了,偶尔会跳字节,大家帮忙看看

[复制链接]
playingaman 提问时间:2018-5-28 15:19 /
        芯片: SMT32F103RET6。
        问题: 在使用SPI 做从机时,接收发送都是DMA模式。 在发送时, DMA偶尔会跳过发送缓存的第2个字节, 调试了好几天, 没有头绪,望大家帮忙看看,
       
        代码:
                1. SPI 初始化

       

  1. //
  2. //       SPI PART
  3. static void m_spi_init(void) {
  4.     GPIO_InitTypeDef GPIO_InitStructure;
  5.     SPI_InitTypeDef  SPI_InitStructure;
  6.     NVIC_InitTypeDef NVIC_InitStructure;
  7.     DMA_InitTypeDef  DMA_InitStructure;
  8.     EXTI_InitTypeDef EXTI_InitStructure;

  9.     // enable clocks
  10.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
  11.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

  12.     // MISO
  13.     GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14;
  14.     GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP;
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  17.     // sck  mosi nss
  18.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_13 | GPIO_Pin_12;
  19.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  20.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  21.     // enable cs  interrupt
  22.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);

  23.     EXTI_InitStructure.EXTI_Line    = EXTI_Line12;
  24.     EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
  25.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  26.     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  27.     EXTI_Init(&EXTI_InitStructure);


  28.     NVIC_InitStructure.NVIC_IRQChannel                   = EXTI15_10_IRQn; //使能外部中断所在的通道
  29.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级 2,
  30.     NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0x01; //子优先级 2
  31.     NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE; //使能外部中断通道
  32.     NVIC_Init(&NVIC_InitStructure);

  33. #if 1
  34.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  35.     DMA_DeInit(DMA1_Channel4); //Set DMA registers to default values
  36.     DMA_StructInit(&DMA_InitStructure);

  37.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; //Address of peripheral the DMA must map to
  38.     DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)m_spi_dma_receive_buff; //Variable to which received data will be stored
  39.     DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
  40.     DMA_InitStructure.DMA_BufferSize         = sizeof(m_spi_dma_receive_buff); //Buffer size
  41.     DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  42.     DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  43.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  44.     DMA_InitStructure.DMA_MemoryDataSize     = DMA_PeripheralDataSize_Byte;
  45.     DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;
  46.     DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
  47.     DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;
  48.     DMA_Init(DMA1_Channel4, &DMA_InitStructure); //Initialise the DMAa

  49.     DMA_DeInit(DMA1_Channel5);               
  50.     DMA_StructInit(&DMA_InitStructure);

  51.     DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;          // Address of peripheral the DMA must map to
  52.     DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)m_spi_dma_send_buf; // Variable from which data will be transmitted
  53.     DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;
  54.     DMA_InitStructure.DMA_BufferSize         = sizeof(m_spi_dma_send_buf);   //Buffer size
  55.     DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
  56.     DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
  57.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  58.     DMA_InitStructure.DMA_MemoryDataSize     = DMA_PeripheralDataSize_Byte;
  59.     DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
  60.     DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
  61.     DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;

  62.     DMA_Init(DMA1_Channel5, &DMA_InitStructure);

  63. #endif

  64.     // enable transfer complete & error interrupt
  65.     NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
  66.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  67.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  68.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  69.     NVIC_Init(&NVIC_InitStructure);
  70.     DMA_ITConfig(DMA1_Channel5, DMA_IT_TC | DMA_IT_TE, ENABLE);

  71.     // enable the dma channel of receiving
  72.     DMA_Cmd(DMA1_Channel4, ENABLE); //Enable the DMA1 - Channel4   


  73.     SPI_Cmd(SPI2, DISABLE);
  74.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  75.     SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
  76.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  77.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  78.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  79.     SPI_InitStructure.SPI_NSS =  SPI_NSS_Hard;
  80.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  81.     SPI_InitStructure.SPI_CRCPolynomial = 7;
  82.     SPI_Init(SPI2, &SPI_InitStructure);

  83.     // enable spi error interrupt
  84.     NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
  85.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  86.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  87.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  88.     NVIC_Init(&NVIC_InitStructure);
  89.     SPI_I2S_ClearFlag(SPI2, SPI_I2S_FLAG_TXE);
  90.     SPI_I2S_ClearFlag(SPI2, SPI_FLAG_MODF);
  91.     SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_ERR, ENABLE);

  92.     // enable dma receive and transmit
  93.     SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);

  94.     // enable spi2 device
  95.     SPI_Cmd(SPI2, ENABLE);
  96. }
复制代码


        2: 发送代码

  1. /*
  2. * @brief: send data via the spi bus.
  3. * @param ack: pointer to the buffer of ack data.
  4. * @param ack_size: size of the ack buffer.
  5. * @param buf: pointer to the data buffer that real be send.
  6. * @param size: size of real data.
  7. */
  8. void board_spi_send(uint8_t *ack, int ack_size, uint8_t *buf, int size) {
  9.     int i, index = 0;

  10.     // copy ACK data to memory
  11.     if (ack != null) {
  12.         for (i = 0; i < ack_size; i++) {
  13.             m_spi_dma_send_buf[index++] = *ack++;
  14.         }
  15.     }
  16.     // copy real data to memory
  17.     if (buf != null) {
  18.         for (i = 0; i < size; i++) {
  19.             m_spi_dma_send_buf[index++] = *buf++;
  20.         }
  21.     }
  22.     // finally, it has data to send.
  23.     if (index != 0) {
  24. #if 1
  25.         DBG_INFO("Fill data intp DMA => ");
  26.         for (i = 0; i < index; i++) {
  27.             printf("0x%02x ", m_spi_dma_send_buf[i]);
  28.         }
  29.         printf("\r\n");
  30. #endif
  31.         // wait for the dma finish its work.
  32.         while ((m_spi_is_sending == true || m_spi_dma_waiting_send == true) && (DMA1_Channel5->CCR & DMA_CCR5_EN));
  33.         // disable dma channel
  34.         DMA1_Channel5->CCR &= (uint16_t)(~DMA_CCR5_EN);
  35.         m_spi_is_sending = false;
  36.         // use to indicate that we are waiting for sending.
  37.         m_spi_dma_waiting_send = true;
  38.         // re-config the address and size
  39.         DMA1_Channel5->CMAR = (uint32_t)m_spi_dma_send_buf;
  40.         // set the buffer size
  41.         DMA1_Channel5->CNDTR = index;
  42.     } else {
  43.         printf("nothing send to spi\r\n");
  44.     }
  45. }
复制代码


        3: CS 中断
  1. //
  2. // interrupt handler routine for spi cs
  3. void EXTI15_10_IRQHandler(void) {

  4.     // the master start to transfer
  5.     if (EXTI_GetITStatus(EXTI_Line12) != RESET) {
  6.         // check whether there are some data waiting for sending.
  7.         if (m_spi_dma_waiting_send == true) {
  8.             DBG_INFO("enable spi send. size = %d\r\n", DMA1_Channel5->CNDTR);
  9.             // set this variable to indicate that we are sending.
  10.             m_spi_is_sending = true;
  11.             // unmark this variable.
  12.             m_spi_dma_waiting_send = false;
  13.             // enable the transmit DMA channel.
  14.             DMA1_Channel5->CCR |= DMA_CCR5_EN;
  15.         }
  16.         EXTI_ClearITPendingBit(EXTI_Line12);
  17.     }  
  18. }
复制代码


        4:DMA 中断
  1. void DMA1_Channel5_IRQHandler(void) {

  2.     if (DMA_GetITStatus(DMA1_IT_TC5) != RESET) {
  3.         DBG_INFO("DMA_INT=> send ack ok! remain size = %d\r\n", DMA1_Channel5->CNDTR);
  4.         // disable the dma channel
  5.         DMA1_Channel5->CCR &= (uint16_t)(~DMA_CCR5_EN);
  6.         m_spi_is_sending = false;
  7.         DMA_ClearITPendingBit(DMA1_IT_TC5);
  8.     }

  9.     if (DMA_GetITStatus(DMA1_IT_TE5) != RESET) {
  10.         DBG_ERROR("some error occured while sending...\r\n");
  11.         // disable the dma channel
  12.         DMA1_Channel5->CCR &= (uint16_t)(~DMA_CCR5_EN);
  13.         m_spi_is_sending = false;
  14.         DMA_ClearITPendingBit(DMA1_IT_TE5);
  15.     }
  16. }
复制代码


        5: SPI 中断
  1. void SPI2_IRQHandler(void) {

  2.     if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_OVR)) {
  3.         DBG_ERROR("spi2 receive overrun!\r\n");
  4.         SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_OVR);
  5.     }
  6.     if (SPI_I2S_GetITStatus(SPI2, SPI_IT_CRCERR)) {
  7.         DBG_ERROR("spi2 crc error!\r\n");
  8.         SPI_I2S_ClearITPendingBit(SPI2, SPI_IT_CRCERR);
  9.     }

  10.     if (SPI_I2S_GetITStatus(SPI2, SPI_IT_MODF)) {
  11.         DBG_ERROR("spi2 mode error!\r\n");
  12.         SPI_I2S_ClearITPendingBit(SPI2, SPI_IT_MODF);
  13.     }
  14. }
复制代码



错误现象:

        调试图片.png

DMA在发送完第一个字节数据后, 跳过了第二个, 直接发送第三个了。。。。。。

看过这个时候的DMA控制寄存器, 值为 209a   字节单位没有改, 都是 Byte。 而且在整个过程中, SPI 和 DMA的错误中断都没有触发! 希望大家帮忙分析一下。。。。


       

收藏 评论4 发布时间:2018-5-28 15:19

举报

4个回答
feixiang20 回答时间:2018-5-29 00:27:28
本帖最后由 feixiang20 于 2018-5-29 00:28 编辑

查看DMA配置里的缓存数据大小BufferSize是你要发送的数据个数

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

playingaman 回答时间:2018-5-29 17:19:45
feixiang20 发表于 2018-5-29 00:27
查看DMA配置里的缓存数据大小BufferSize是你要发送的数据个数

在发送之前CS中断里打印出来 是预期的  现在把程序用 STM32F103VCT6 100PIN  测试, 已经跑了一下午没出问题了
七哥 回答时间:2018-5-30 01:49:10
有原理图吗?你是搭的电路,还是画的PCB板上的电路。
从你的现象来看的话(首先我猜想你的 m_spi_dma_receive_buff为2),SPI片选有没有可能,受干扰,而产生一个上升沿脉冲呢?

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

黑皮男 回答时间:2018-5-30 09:09:32
我的spi 从机的时候也是偶尔会出错,有点郁闷

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版