Following this post I managed to setup my Nucleo board with two SPI devices & working interrupts with 1ms periodic 6 bytes payload transmission. My idea was to trigger the two SPI modules together as to have them run in parallel but something is preventing me from achieving that:
- expected: SPI1 & SPI2 sequences are 99% overlapped, only dephased by a couple of system clocks
- observed: the first bytes are overlapping as expected but then the first SPI module that was called (SPI1) seems to take precedence and complete its transmission before allowing SPI2 to terminate his. If SPI2 is called first then it will finish first.
Here are my main code pieces:
volatile uint8_t t[6] = {0x50, 0x60, 0x70, 0x80, 0x90, 0x10};
volatile uint8_t r[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
volatile uint8_t transmit_count1 = 6, transmit_count2 = 6, transmit_count3 = 6;
volatile uint8_t transmit_index1 = 0, transmit_index2 = 0, transmit_index3 = 0;
void do_SPI_ISR(){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // SS1
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // SS2
LL_SPI_Enable(SPI1);
LL_SPI_Enable(SPI2);
transmit_index1 = transmit_index2 = transmit_index3 = 0;
transmit_count1 = transmit_count2 = transmit_count3 = 6;
LL_SPI_EnableIT_TXE(SPI1); // enable SPI1 TX interrupt
LL_SPI_EnableIT_TXE(SPI2); // enable SPI2 TX interrupt
LL_SPI_TransmitData8(SPI1, t[transmit_index1]);
LL_SPI_TransmitData8(SPI2, t[transmit_index2]);
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){
// SS are set HIGH by interrupts, remain here until that happens for both lines
}
}
void SPI1_ISR_callback(){
if (transmit_index1 < transmit_count1 - 1){
transmit_index1 ++;
LL_SPI_TransmitData8(SPI1, t[transmit_index1]);
} else {
LL_SPI_DisableIT_TXE(SPI1);
transmit_index1 = 0;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
LL_SPI_Disable(SPI1);
}
}
void SPI2_ISR_callback(){
if (transmit_index2 < transmit_count2 - 1){
transmit_index2 ++;
LL_SPI_TransmitData8(SPI2, t[transmit_index2]);
} else {
LL_SPI_DisableIT_TXE(SPI2);
transmit_index2 = 0;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
LL_SPI_Disable(SPI2);
}
}
I did not tune anything regarding interrupt priorities, both SPIs have 0/0 priority. I was assuming that both interrupts would fire in turn and trigger bytes transmission but it's not the case, maybe some interrupt event constantly fire on SPI1, thus preventing SPI2 fire his? I tried removing all error & receive interrupts but that didn't change the outcome.
Edit, more code:
void SPI1_IRQHandler(void)
{
/* USER CODE BEGIN SPI1_IRQn 0 */
if (LL_SPI_IsActiveFlag_TXE(SPI1)){
SPI1_ISR_callback();
}
/* USER CODE END SPI1_IRQn 0 */
/* USER CODE BEGIN SPI1_IRQn 1 */
/* USER CODE END SPI1_IRQn 1 */
}
/**
* @brief This function handles SPI2 global interrupt.
*/
void SPI2_IRQHandler(void)
{
/* USER CODE BEGIN SPI2_IRQn 0 */
if (LL_SPI_IsActiveFlag_TXE(SPI2)){
SPI2_ISR_callback();
}
/* USER CODE END SPI2_IRQn 0 */
/* USER CODE BEGIN SPI2_IRQn 1 */
/* USER CODE END SPI2_IRQn 1 */
}
Edit 2 (25/05/2020), with TXE flag managed from main app and interrupts disabled:
Corresponding code:
void do_SPI_ISR(){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // SS1
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); // SS2
LL_SPI_Enable(SPI1);
LL_SPI_Enable(SPI2);
transmit_index1 = transmit_index2 = transmit_index3 = 0;
transmit_count1 = transmit_count2 = transmit_count3 = 6;
//LL_SPI_EnableIT_TXE(SPI1); // enable SPI1 TX interrupt
//LL_SPI_EnableIT_TXE(SPI2); // enable SPI2 TX interrupt
LL_SPI_TransmitData8(SPI1, t[transmit_index1]);
LL_SPI_TransmitData8(SPI2, t[transmit_index2]);
while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET || HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){
if (LL_SPI_IsActiveFlag_TXE(SPI1)){
SPI1_ISR_callback();
}
if (LL_SPI_IsActiveFlag_TXE(SPI2)){
SPI2_ISR_callback();
}
}
}
Any help much appreciated