芯片: SMT32F103RET6。
问题: 在使用SPI 做从机时,接收发送都是DMA模式。 在发送时, DMA偶尔会跳过发送缓存的第2个字节, 调试了好几天, 没有头绪,望大家帮忙看看,
代码:
1. SPI 初始化
- //
- // SPI PART
- static void m_spi_init(void) {
- GPIO_InitTypeDef GPIO_InitStructure;
- SPI_InitTypeDef SPI_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- DMA_InitTypeDef DMA_InitStructure;
- EXTI_InitTypeDef EXTI_InitStructure;
- // enable clocks
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
- // MISO
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- // sck mosi nss
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_13 | GPIO_Pin_12;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- // enable cs interrupt
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
- EXTI_InitStructure.EXTI_Line = EXTI_Line12;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;
- EXTI_Init(&EXTI_InitStructure);
- NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能外部中断所在的通道
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //抢占优先级 2,
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级 2
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
- NVIC_Init(&NVIC_InitStructure);
- #if 1
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- DMA_DeInit(DMA1_Channel4); //Set DMA registers to default values
- DMA_StructInit(&DMA_InitStructure);
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; //Address of peripheral the DMA must map to
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)m_spi_dma_receive_buff; //Variable to which received data will be stored
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
- DMA_InitStructure.DMA_BufferSize = sizeof(m_spi_dma_receive_buff); //Buffer size
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel4, &DMA_InitStructure); //Initialise the DMAa
- DMA_DeInit(DMA1_Channel5);
- DMA_StructInit(&DMA_InitStructure);
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR; // Address of peripheral the DMA must map to
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)m_spi_dma_send_buf; // Variable from which data will be transmitted
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- DMA_InitStructure.DMA_BufferSize = sizeof(m_spi_dma_send_buf); //Buffer size
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel5, &DMA_InitStructure);
- #endif
- // enable transfer complete & error interrupt
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- DMA_ITConfig(DMA1_Channel5, DMA_IT_TC | DMA_IT_TE, ENABLE);
- // enable the dma channel of receiving
- DMA_Cmd(DMA1_Channel4, ENABLE); //Enable the DMA1 - Channel4
- SPI_Cmd(SPI2, DISABLE);
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
- SPI_Init(SPI2, &SPI_InitStructure);
- // enable spi error interrupt
- NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- SPI_I2S_ClearFlag(SPI2, SPI_I2S_FLAG_TXE);
- SPI_I2S_ClearFlag(SPI2, SPI_FLAG_MODF);
- SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_ERR, ENABLE);
- // enable dma receive and transmit
- SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
- // enable spi2 device
- SPI_Cmd(SPI2, ENABLE);
- }
复制代码
2: 发送代码
- /*
- * @brief: send data via the spi bus.
- * @param ack: pointer to the buffer of ack data.
- * @param ack_size: size of the ack buffer.
- * @param buf: pointer to the data buffer that real be send.
- * @param size: size of real data.
- */
- void board_spi_send(uint8_t *ack, int ack_size, uint8_t *buf, int size) {
- int i, index = 0;
- // copy ACK data to memory
- if (ack != null) {
- for (i = 0; i < ack_size; i++) {
- m_spi_dma_send_buf[index++] = *ack++;
- }
- }
- // copy real data to memory
- if (buf != null) {
- for (i = 0; i < size; i++) {
- m_spi_dma_send_buf[index++] = *buf++;
- }
- }
- // finally, it has data to send.
- if (index != 0) {
- #if 1
- DBG_INFO("Fill data intp DMA => ");
- for (i = 0; i < index; i++) {
- printf("0x%02x ", m_spi_dma_send_buf[i]);
- }
- printf("\r\n");
- #endif
- // wait for the dma finish its work.
- while ((m_spi_is_sending == true || m_spi_dma_waiting_send == true) && (DMA1_Channel5->CCR & DMA_CCR5_EN));
- // disable dma channel
- DMA1_Channel5->CCR &= (uint16_t)(~DMA_CCR5_EN);
- m_spi_is_sending = false;
- // use to indicate that we are waiting for sending.
- m_spi_dma_waiting_send = true;
- // re-config the address and size
- DMA1_Channel5->CMAR = (uint32_t)m_spi_dma_send_buf;
- // set the buffer size
- DMA1_Channel5->CNDTR = index;
- } else {
- printf("nothing send to spi\r\n");
- }
- }
复制代码
3: CS 中断
- //
- // interrupt handler routine for spi cs
- void EXTI15_10_IRQHandler(void) {
- // the master start to transfer
- if (EXTI_GetITStatus(EXTI_Line12) != RESET) {
- // check whether there are some data waiting for sending.
- if (m_spi_dma_waiting_send == true) {
- DBG_INFO("enable spi send. size = %d\r\n", DMA1_Channel5->CNDTR);
- // set this variable to indicate that we are sending.
- m_spi_is_sending = true;
- // unmark this variable.
- m_spi_dma_waiting_send = false;
- // enable the transmit DMA channel.
- DMA1_Channel5->CCR |= DMA_CCR5_EN;
- }
- EXTI_ClearITPendingBit(EXTI_Line12);
- }
- }
复制代码
4:DMA 中断
- void DMA1_Channel5_IRQHandler(void) {
- if (DMA_GetITStatus(DMA1_IT_TC5) != RESET) {
- DBG_INFO("DMA_INT=> send ack ok! remain size = %d\r\n", DMA1_Channel5->CNDTR);
- // disable the dma channel
- DMA1_Channel5->CCR &= (uint16_t)(~DMA_CCR5_EN);
- m_spi_is_sending = false;
- DMA_ClearITPendingBit(DMA1_IT_TC5);
- }
- if (DMA_GetITStatus(DMA1_IT_TE5) != RESET) {
- DBG_ERROR("some error occured while sending...\r\n");
- // disable the dma channel
- DMA1_Channel5->CCR &= (uint16_t)(~DMA_CCR5_EN);
- m_spi_is_sending = false;
- DMA_ClearITPendingBit(DMA1_IT_TE5);
- }
- }
复制代码
5: SPI 中断
- void SPI2_IRQHandler(void) {
- if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_OVR)) {
- DBG_ERROR("spi2 receive overrun!\r\n");
- SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_OVR);
- }
- if (SPI_I2S_GetITStatus(SPI2, SPI_IT_CRCERR)) {
- DBG_ERROR("spi2 crc error!\r\n");
- SPI_I2S_ClearITPendingBit(SPI2, SPI_IT_CRCERR);
- }
- if (SPI_I2S_GetITStatus(SPI2, SPI_IT_MODF)) {
- DBG_ERROR("spi2 mode error!\r\n");
- SPI_I2S_ClearITPendingBit(SPI2, SPI_IT_MODF);
- }
- }
复制代码
错误现象:
DMA在发送完第一个字节数据后, 跳过了第二个, 直接发送第三个了。。。。。。
看过这个时候的DMA控制寄存器, 值为 209a 字节单位没有改, 都是 Byte。 而且在整个过程中, SPI 和 DMA的错误中断都没有触发! 希望大家帮忙分析一下。。。。
|
查看DMA配置里的缓存数据大小BufferSize是你要发送的数据个数
评分
查看全部评分
在发送之前CS中断里打印出来 是预期的 现在把程序用 STM32F103VCT6 100PIN 测试, 已经跑了一下午没出问题了
从你的现象来看的话(首先我猜想你的 m_spi_dma_receive_buff为2),SPI片选有没有可能,受干扰,而产生一个上升沿脉冲呢?
评分
查看全部评分
评分
查看全部评分