2024-07-25 07:59 AM
I have an STM32-L4P5DK connected to an external ADC, with SPI2 configured to read ADC samples on every falling edge of the DRDY signal. The DMA1 configuration is as follows:
DMA1 CHANNEL1: DMA_GENERATOR0
DMA1 CHANNEL2: SPI2_TX
DMA1 CHANNEL3: SPI2_RX
The DRDY pin is connected to EXTI1. On each falling edge of DRDY, DMA_GENERATOR0 generates a request to set the Chip Select pin low. The SPI_TX DMA request is synchronized with the rising edge of DRDY, so SPI_TX transmits dummy bytes to read the ADC data via SPI_RX DMA request, which is also synchronized with the EXTI1 rising edge. Once the SPI transmission is complete, I set the Chip Select pin high in the `HAL_SPI_TxCpltCallback` function.
The problem is that the Chip Select pin goes high before the SPI transmission completes. However, if I add a delay using a while() loop, the Chip Select timing shifts correctly.
Why is this happening, and how can I ensure that the Chip Select pin goes high only after the SPI transmission is completely finished?
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, 1); //callback function without delay
}
for the above function , I get the below output.
fig 1:
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
uint8_t i =21;
while(--i) // added delay to shift CS pin HIGH state
{
__NOP();
}
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, 1);
}
for the above function , I get the below output.
fig2:
Scope output:
>> yellow - DRDY , green - CS , red - SCK , blue - MOSI
2024-07-25 08:49 AM - edited 2024-07-25 08:49 AM
> Why is this happening
The DMA transfer completes when the last byte of data is sent to the peripheral. Since the peripheral has a FIFO, this happens before some bytes before the data is actually sent out. (Even without a FIFO, it would happen before the last byte is sent.)
> and how can I ensure that the Chip Select pin goes high only after the SPI transmission is completely finished?
Poll the SPI BSY bit and wait for it to be 0 before de-asserting CS.
This is actually covered in the RM:
2024-07-26 02:24 AM - edited 2024-07-26 02:26 AM
Hi TDK,
I tried polling the SPI BSY bit, but it did not work. The CS pin becomes high even before the SPI transmission starts.
I have resolved the chip select issue by starting the timer in the `HAL_GPIO_EXTI_Callback` function. After 120us (since I am sampling at a rate of 8000sps, i.e., every 125 microseconds), I make the chip select pin HIGH in the `HAL_TIM_PeriodElapsedCallback` function. It works fine.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == TIM4) {
HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET);
HAL_TIM_Base_Stop(&htim4);
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
HAL_TIM_Base_Start(&htim4);
}
Regards,
AJ
2024-07-26 02:31 AM - edited 2024-07-26 02:33 AM
Another issue I am facing is that, although I see the expected output on the scope, the first four bytes (0th byte to 3rd byte) from the SPI read are always junk. The correct data starts only from the 4th byte.
For example,
adc_buf = [0x00, 0x6f, 0x10, 0x0d, 0x01, 0xff, 0x00], but on the scope, the first byte is 0x01, the second byte is 0xff, and so on.
Why is this happening?
regards,
AJ
2024-07-26 05:37 AM
> I tried polling the SPI BSY bit, but it did not work.
It should work. Show the code.
2024-07-26 05:41 AM
Sounds like there is data in the FIFO that hasn't been read out properly. Possibly some other code bug. Hard to know without seeing more info.
2024-07-26 06:36 AM
>Sounds like there is data in the FIFO that hasn't been read out properly
I have explained my application in the thread. The first four bytes are unnecessary data. I have verified the threshold bit (FRXTH set to 1). I also tried reading four bytes initially to flush the RXFIFO, but the issue is still not resolved. I read 27 bytes (status - 3 bytes, 8 channel ADC data - 24 bytes) of data every 125 microseconds after the DRDY signal.
Regards,
AJ
2024-07-26 07:26 AM
Use HAL_SPI_TransmitReceive_DMA since you are both sending and receiving data. And you can set CS high on the receive complete callback since the transfer will be done when the last byte is received, no need to poll for BSY.