SPI loopback con DMA

5

Estoy utilizando la placa de descubrimiento STM32F4 y estoy intentando obtener un loopback SPI con DMA.

He ejecutado con éxito un bucle "SPI solo", pero ahora quiero usar DMA además de SPI, aquí están las funciones que estoy usando:

Inicialización de SPI

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 PA4 high

  // enable SPI1 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_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  

  return;
}        

Configuración de DMA:

void DMA_Config()
{  
DMA_InitTypeDef DMA_InitStructure;   
NVIC_InitTypeDef NVIC_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

DMA_ClearFlag(DMA2_Stream2,        DMA_FLAG_FEIF2|DMA_FLAG_DMEIF2|DMA_FLAG_TEIF2|DMA_FLAG_HTIF2|DMA_FLAG_TCIF2);
DMA_Cmd(DMA2_Stream2, DISABLE);
while (DMA2_Stream2->CR & DMA_SxCR_EN);
DMA_DeInit(DMA2_Stream5);
DMA_StructInit(&DMA_InitStructure);

DMA_InitStructure.DMA_Channel = DMA_Channel_3;
DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t) &(SPI1->DR);
DMA_InitStructure.DMA_Memory0BaseAddr  = (uint32_t) &spiTxBuff;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize  = SPI_TX_MAX;
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_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode  = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority  = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;

DMA_Init(DMA2_Stream5, &DMA_InitStructure); 

/**
configuration of the interrupts of DMA
******************************************************/
DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);  
return;
}

Función de escritura SPI:

void SPI1_Write(uint8_t *txBuff,int length,tSPI_Callback fct)
{
 DMA2_Stream5->M0AR = (uint32_t) &spiTxBuff;
 DMA_Cmd(DMA2_Stream5, ENABLE);
 SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
 SPI_Cmd(SPI1, ENABLE);
}

Los datos recibidos se escriben en el búfer Rx utilizando el controlador de interrupciones SPI.

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

Llamo a estas funciones en main() de la siguiente manera:

main.c:

DMA_Config();
init_SPI1();
SPI1_Write(spiTxBuff,SPI_TX_MAX,(void*)0); 

Usando un depurador, encontré que, en el registro de estado de alta interrupción de DMA, TCIF5 (indicador de transferencia completa) y HTIF5 (indicador de media transferencia completa) están configurados en 1, lo que significa que la transferencia se realizó con éxito, en mi opinión, Sin embargo, no obtuve ningún dato en el SPI Rx Buffer. La segunda cosa extraña es que ni DMA Interrupt ni SPI Interrupt se activan. ¿Podría ayudarme, por favor, a descubrir qué es lo que está mal en mi código?

    
pregunta fedi

1 respuesta

0

Hay algunos errores que he corregido y obtengo el resultado esperado:

1) La interrupción de SPI Rx no está configurada, se perdió esta línea SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE)

2) En la función DMA_Config Las interrupciones de DMA1 están habilitadas en lugar de DMA2, esta línea NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;

Esta es la solución

de trabajo.     
respondido por el fedi

Lea otras preguntas en las etiquetas