cancel
Showing results for 
Search instead for 
Did you mean: 

Data not updating on each UART_RxCpltCallback

robotwhisperer
Associate II

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. 

robotwhisperer_0-1758220233030.png

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")));

 

8 REPLIES 8
TDK
Super User

Where is your code that takes data and translates that into a sawtooth wave that we see? Surely the issue lies in there somewhere.

If you feel a post has answered your question, please click "Accept as Solution".
MNapi
Senior III

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.

Saket_Om
ST Employee

Hello @robotwhisperer 


@robotwhisperer wrote:

All this should happen at 2KHz,


Why it should happen at 2Khz?


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.
Saket_Om

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. 

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. 

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.

robotwhisperer
Associate II

I have some updates on this problem. It is not solved, but infact may be deeper that what I initially thought. 

  • I have updated my code to allow packet-by-packet debugging so I can control when the packet is sent (no longer constantly streaming at 2KHz) and inspect the contents of the UART buffer immediately after.
  • The sending board is set up to send one packet at the press of the user button. It is not being debugged using the STLink in STM32CubeIDE
  • Each press toggles the RED LED on the sending board.
  • The receiving board is being debugged using the STLink in STM32CubeIDE. I am monitoring the firmware.serial_communication_.rx_buffer_ (this is the UART rx buffer) contents using the live expressions monitor. 
  • Each time the HAL_UART_RxCpltCallback() is triggered, it toggles the RED LED on the receiving board. 
  • Sometimes, even though the HAL_UART_RxCpltCallback() is triggered, verified using the RED LED on the board toggling, as well as scoping the UART line to see that the data was indeed sent, the firmware.serial_communication_.rx_buffer_ contents do not change. So far, I cannot explain this. This behaviour does not happen every time, and it does not occur in a regular or repeating fashion (e.g. if every Nth transmission is missed, something of that sort), it is truly random. 
  • For this test, I have commented out the MPU_Config(), SCB_EnableICache() and SCB_EnableDCache() functions, so the MPU and cache should be completely disabled as per @MNapi 's comment. 
  • I deprioritized all other interrupts apart from the UART Rx DMA interrupt, but this problem did not go away.

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!  

 

 

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 */