本文介绍了如何使用stm32F4设置中断驱动的SPI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有CMSIS库的STM32F4板,我想设置一个中断驱动的SPI,这意味着每次SPI外设发送一个字节时都会触发一个中断.初始化功能如下:

I'am using STM32F4 board with CMSIS library and I want setup an interrupt driven SPI, it means an interrupt is triggered each time a byte is sent by the SPI peripheral. The initiaisation function is as below:

void init_SPI1(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  GPIO_InitTypeDef GPIO_InitStruct;
  SPI_InitTypeDef SPI_InitStruct;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5|GPIO_Pin_4;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  // connect SPI1 pins to SPI alternate function
  //GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

  //Set chip select high
  GPIOA->BSRRL |= GPIO_Pin_4; // set PE4 high

  // enable peripheral clock
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

  /* configure SPI1 in Mode 0
   * CPOL = 0 --> clock is low when idle
   * CPHA = 0 --> data is sampled at the first edge
   */
  SPI_StructInit(&SPI_InitStruct); // set default settings
  SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
  SPI_InitStruct.SPI_Mode = SPI_Mode_Master;     // transmit in master mode, NSS pin has to be always high
  SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
  SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;        // clock is low when idle
  SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;      // data sampled at first edge
  SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ; // set the NSS management to internal and pull internal NSS high
  SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
  SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
  SPI_Init(SPI1, &SPI_InitStruct);

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* Enable SPI1*/
  SPI_Cmd(SPI1, ENABLE);
  return;
}

然后,我仅将SPI_MOSI环回到SPI_MISO,并使用一个传输数据的功能(一个非常基本的功能,该功能从缓冲区中获取数据,然后使用CMSIS功能进行传输).问题在于,当SPI中断被触发时,程序不会从处理程序中退出.处理程序函数看起来像这样:

Then i just loopback SPI_MOSI to SPI_MISO and use a function that transmit the data (a very basic function that takes data from a buffer and then uses CMSIS functions for the transmission). The problem is that when the SPI interrupt is triggered, the program won't get out from the handler. the handler function looks lihe this:

void SPI1_IRQHandler()
{
 int a;
 a++;
 SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_TXE);
 return;
}

是CMSIS库中的问题,还是我没有以良好的方式配置SPI中断?请引导我到正确的位置.

Is it a problem in the CMSIS library, or I am not configuring the SPI interrupt in the good way? Please guide me to the right point.

编辑

这是我用于数据传输的功能

This is the function i use for data transmission

void write_SPI1()
{
 int i;

   for (i=0;i<SPI_TX_MAX; i++)
  {
   SPI_I2S_SendData(SPI1,spiTxBuff[i]);
   SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);
  }
}

和中断有关的数据接收,它只是在接收新数据时填充spiRxBuff.

and the interruption deals with the data reception, it just fill spiRxBuff when receiving new data.

void SPI1_IRQHandler()
{
 while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)== RESET);

  spiRxBuff[spiRxCount]= SPI_I2S_ReceiveData(SPI1);
  spiRxCount++;
}

用于接收/发送的变量声明如下:

The variable used for Reception / Transmission are declared as below :

uint8_t spiTxBuff[SPI_TX_MAX] = {0x01,0x02,0x03,0x04,0x05,0x06};
uint8_t spiRxBuff[SPI_RX_MAX];
static volatile int spiRxCount= 0;  // used in SPI1_IRQHandler

现在奇怪的是我在spiRxBuff中有{0x01,0x02,0x03,0x05,0x06}而不是{0x01,0x02,0x03,0x04,0x05,0x06},但是使用调试模式,spiRxBuff中的数据是正确的,您认为出了什么问题?

what is strange now is that i'am having {0x01,0x02,0x03,0x05,0x06} in spiRxBuff instead of {0x01,0x02,0x03,0x04,0x05,0x06}, but using debug mode the data in spiRxBuff are correct, what goes wrong in your opinion ?

推荐答案

您没有显示执行传输的功能,所以我不知道您要完成什么工作

You did not show the function doing the transmit, so I don't know exactly what are you trying to accomplish

循环发送

如果要从某个函数(循环)进行传输,则根本不需要中断,只需确保在传输之前已设置TXE标志.请注意,您必须以某种方式交错发送和接收.

If you are transmitting from a function (in a loop), then you don't need interrupts at all, just make sure that the TXE flag is set before you transmit. Note that you have to interleave sending and receiving somehow.

void SPI1_Transmit(uint8_t *send, uint8_t *receive, int count) {
  while(count-- > 0) {
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)!=SET) {
      if(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==SET)
        *receive++ = SPI_I2S_ReceiveData(SPI1);
    }
    SPI_I2S_SendData(SPI1, *send++);
  }
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)!=SET) {
    /* wait for the last incoming byte */
  }
  *receive++ = SPI_I2S_ReceiveData(SPI1);
}

从中断发送

只要SPI设备不忙于发送,就设置TXE中断标志.如果您在中断处理程序中不执行任何操作,它将立即一次又一次触发中断.您无法手动清除它,而是要发送另一个字节,并在发送最后一个字节之前重置发送中断使能标志.

The TXE interrupt flag is set as long as the SPI device is not busy sending. If you don't do something about it in the interrupt handler, it will trigger an interrupt immediately again and again. You can't clear it manually, but by transmitting another byte, and resetting the transmit interrupt enable flag before sending the last byte.

volatile int spi1_tx_count, spi1_rx_count;
uint8_t *spi1_tx_ptr;
volatile uint8_t *spi1_rx_ptr;
/* set these global variables before enabling interrupts */

void SPI1_IRQHandler() {
  if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_TXE) == SET) {
    if(--spi1_tx_count < 1)
      SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, DISABLE);
    SPI_I2S_SendData(SPI1, *spi1_tx_ptr++);
  }
  if(SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_RXNE) == SET) {
    *spi_rx_ptr++ = SPI_I2S_ReceiveData(SPI1);
    spi1_rx_count++;
  }
}

使用DMA

以上示例使用处理器的功率和周期来完成只能由DMA控制器处理的任务.如果您以2 MBit/s的速度与外设通信,则会有很多(如果不是全部)处理器周期.

The above examples are using processor power and cycles for a task that can be handled by the DMA conroller alone. A lot of (if not all) processor cycles, if you are talking to a peripheral at 2 MBit/s.

有关示例,请参见库中的Project/STM32F4xx_StdPeriph_Examples/SPI/SPI_TwoBoards.

See Project/STM32F4xx_StdPeriph_Examples/SPI/SPI_TwoBoards in the library for an example.

这篇关于如何使用stm32F4设置中断驱动的SPI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-13 14:28