2018-12-12 12:30 PM
hello...
ok so I have managed to get the SPI port on my 446RE nucleo board sending out data to my slave Bus Expander IC via the DMA peripherial.
I am new to the DMA peripheral and not sure if I even need to use it over using interrupt control, but would like to get a little more confident with the SPI DMA use. any help of how it all working and tips on coding would be very much appreciated
I am using the following code, to send 3 bytes to the DMA
uint8_t MCP23017_INIT[] ={ WR_ADR_0, 0x0A, 0xAA};
//uint8_t MCP23017_INITA[] ={ WR_ADR_0, IODIRA, ALL_INPUT, 0x00, 0xFF, 0xFF, 0xFF, 0x8A, 0x00};
uint8_t MCP23017_INITB[] ={ WR_ADR_0, 0x10, 0x00};
uint8_t MCP23017_INITB2[] ={ WR_ADR_0, 0x1A, 0xFF};
// ALL_OUTPUT, 0x00, 0x00, ALL_PINS, NO_PINS };
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) MCP23017_INIT, 3 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) MCP23017_INITB, 3 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) MCP23017_INITB2, 3 ) ;
this is my DMA CONFIG.
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_tx;
/* SPI2 init function */
void MX_SPI2_Init(void)
{
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(spiHandle->Instance==SPI2)
{
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI2 GPIO Configuration
PC1 ------> SPI2_MOSI
PC2 ------> SPI2_MISO
PB10 ------> SPI2_SCK
PB12 ------> SPI2_NSS
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* SPI2 DMA Init */
/* SPI2_TX Init */
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi2_tx.Init.Mode = DMA_NORMAL;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(spiHandle, hdmatx, hdma_spi2_tx);
/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);
}
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
if(spiHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspDeInit 0 */
/* USER CODE END SPI2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_SPI2_CLK_DISABLE();
/**SPI2 GPIO Configuration
PC1 ------> SPI2_MOSI
PC2 ------> SPI2_MISO
PB10 ------> SPI2_SCK
PB12 ------> SPI2_NSS
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_2);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_12);
/* SPI2 DMA DeInit */
HAL_DMA_DeInit(spiHandle->hdmatx);
/* SPI2 interrupt Deinit */
HAL_NVIC_DisableIRQ(SPI2_IRQn);
/* USER CODE BEGIN SPI2_MspDeInit 1 */
/* USER CODE END SPI2_MspDeInit 1 */
}
}
I also have two interrupts set up,
1) FIFO Half Full
2) SPI TX Complete
I am not sure what I have to do in sequentially sending SPI data,
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) MCP23017_INIT, 3 ) ;
If I want 3 or 10 of the above lines one after the other, i.e. sending SPI TX Data
what do I need to test for to ensure all SPI data gets sent, and the SPI peripheral is free to accept the next packet of SPI data.
do I need to poll,?
do I need to set a software flag in the tx complete interrupt, that then allows me to send the next spi data ???
so I want to do this
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) MCP23017_INIT, 3 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) DATA1, 30 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) DATA2, 3 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) DATA3, 3 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) DATA4, 3 ) ;
HAL_SPI_Transmit_DMA( &hspi2, (uint8_t*) DATA5, 3 ) ;
What do I need in between each line above to ensure all SPI DMA data is sequentially sent when ready.
I am assuming I need to wait until the SPI data has been transmitted before trying to send the next packet of data, I know the DMA has a FIFO, but not even sure If i want or need to use this?
DMA direct mode may be better
any help with this DMA spi peripheral will be very much appreciatyed
Regards
2018-12-13 05:19 AM
Hi @JHERI ,
You need to wait that SPI becomes ready to perform a new transmission. In the examples provided in Cube packages, it is implemented this way:
while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY)
{
}
You can start with a project that you configure by yourself using STM32CubeMX, then add processing code taking as reference an example like STM32Cube_FW_F4_V1.23.0\Projects\STM32F4-Discovery\Examples\SPI\SPI_FullDuplex_ComDMA.
Hope this will bring you some help.
-Amel
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.