2025-09-18 11:38 AM
I have a 2-board communication project set up with 2 NUCLEO-H753ZI boards, where they communicate over UART. The sender side sends a 22-byte stream of data that is received by the receiver side and gets parsed into data. This data can then be streamed to a PC over Ethernet.
Inside of the UART_RxCpltCallback, I toggle the Red on-board LED, which gives me the rate at which packets are coming in. Inside the UART_TxCpltCallback I am calling a function that takes the data from the UART buffer, and moves it into a member variable of an object. All this should happen at 2KHz, but for some reason the data is only updating every few seconds, and it is not a specific rate at which it updates, it seems random. The graph might better illustrate what I am talking about. The graph *should* look like a sawtooth waveform.
The confusing part is that the LEDs work as expected, i.e. those blocks of code that are responsible for getting the data where it needs to be are surely executing, they just don't seem to do the thing I think they are doing.
AFAIK the receive buffer being used is in a non-cacheable region, so the issue should not be MPU or cache related.
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x0;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.BaseAddress = 0x30010000;
MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
MPU_InitStruct.SubRegionDisable = 0x0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.BaseAddress = 0x30020000;
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER3;
MPU_InitStruct.BaseAddress = 0x30040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512B;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
Linked script snippet:
{
. = ALIGN(8);
. = ABSOLUTE(0x30000000);
*(.RxUsartBuffer)
. = ALIGN(8);
. = ABSOLUTE(0x30008000);
*(.TxBuffer)
. = ALIGN(8);
. = ABSOLUTE(0x30010000);
*(.Adc1Buffer)
. = ALIGN(8);
. = ABSOLUTE(0x30014000);
*(.Adc2Buffer)
. = ALIGN(8);
. = ABSOLUTE(0x30018000);
*(.Adc3Buffer)
. = ALIGN(8);
. = ABSOLUTE(0x30040000);
*(.RxDecripSection)
. = ALIGN(8);
. = ABSOLUTE(0x30040100);
*(.TxDecripSection)
. = ALIGN(8);
. = ABSOLUTE(0x30040200);
*(.Rx_PoolSection)
. = ALIGN(8);
} >RAM_D2
and the buffer
std::array<uint8_t, SerialRxBuffer::kSize> SerialCommunication::rx_buffer_
__attribute__((section(".RxUsartBuffer")));
2025-09-18 11:54 AM
Where is your code that takes data and translates that into a sawtooth wave that we see? Surely the issue lies in there somewhere.
2025-09-18 2:52 PM - edited 2025-09-18 2:52 PM
The first thing to check:
UART_TxCpltCallback functions correctly in both DMA and interrupt modes, but it does not operate in blocking mode.
I'm not sure which chip you're using, but I suspect it might be an STM32H series (Cortex-M7). Try disabling all memory protection features and see if that resolves the issue.
2025-09-19 3:44 AM
Hello @robotwhisperer
@robotwhisperer wrote:
All this should happen at 2KHz,
Why it should happen at 2Khz?
2025-09-19 7:32 AM
Why it should happen at 2Khz?
The sending side is sending packets at 2KHz which is what triggers the callback on the receiver side at 2KHz, the callback does trigger reliably at 2KHz.
2025-09-19 7:40 AM
I'm not sure which chip you're using
You're right, it is a Cortex M7. I am using the STM32H753ZI on the NUCLEO-H753ZI as mentioned in the post.
UART_TxCpltCallback functions correctly in both DMA and interrupt modes, but it does not operate in blocking mode.
I am not using any blocking calls anywhere, neither on the sender side nor on the receiver side.
Try disabling all memory protection features and see if that resolves the issue.
I have added the linker script and MPU_Init() function, which shows that the region where the receive buffer is stored is not handled by the MPU (I am sure this is the case, but please correct me if I am wrong), so this should not be the problem.
2025-09-19 8:18 AM
Ok you are not using any blocking calls. USART interrupt is enabled in CubeMX. If you're using DMA you have enabled DMA for both TX and RX.This part is fine.
I use those H chips because they are fast and have enough memory for most projects. But each time something does not work the cortex memory protection unit control setting is the problem. If do not need it and keep it disabled and all suddenly works.
CubeMX has bunch of working examples, go to CubeMX example selector. I am pretty sure you can find there working code.
2025-09-19 9:27 AM
I have some updates on this problem. It is not solved, but infact may be deeper that what I initially thought.
Here is the code that @TDK requested.
// This is the function that takes the UART Rx data and puts it into the
// firmware object's member variable.
void Firmware::SetSensorDataFromUart(const SensorData &sensor_data_received) {
auto priority_mask_state = InterruptsDisable();
HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
for (size_t i = 0; i < kNumberOfSensors; i++) {
sensor_data_raw_[i] = sensor_data_received[i];
}
// Update the timestamp when data is received via UART
sample_timestamp_us_ = execution_clock_.GetMicroseconds();
InterruptsEnable(priority_mask_state);
}
Let me know if there is more information required to help you in helping me. Thank you!
2025-09-19 2:57 PM
Do you have the code pointing to proper USART , like USART1 in this example?. Do you have any other code running? strip it to bare minimum and run only USART.
while(1)
{
if (HAL_UART_Receive_IT(&huart1, tr_data, sizeof(tx_data) - 1) != HAL_OK)
{
}
}
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
}
}
/* USER CODE END 4 */