cancel
Showing results for 
Search instead for 
Did you mean: 

STM32MP1 RPMsg doesn't create channels after updating CubeMX and CubeIDE to latest versions

NRoux.1
Associate

I'm trying to debug a problem in my system where on rare occasions, a message gets dropped in the M4->A7 direction of RPMsg channels (M4 sends it without error and A7 never sees a message arrive). The project was started a long time ago using an older version of CubeMX and CubeIDE (versions 5.4.0 and 1.7.0 respectively), so as a first step I wanted to update the M4's SDK and tools to the latest versions to make sure it's not a driver issue that's already been fixed (versions 6.8.0 and 1.12.0). After updating the tools and regenerating the code (and resolving a couple of FreeRTOS conflicts since a couple files moved), everything seems to be running except that the RPMsg TTY devices aren't showing up in /dev/.

Since getting those devices to show up is basically just init code at the start of main in the M4 and this code works in the older version of the SDK, I was hoping someone could do a quick sanity check of my startup code and make sure it's correct for the latest versions of the RPMsg and VirtualUart drivers. I would normally run this on the debugger to try to get additional information, but unfortunately RPMsg is one of the few things you can't use while in engineering mode.

In main.c:

int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
  // Cube MX doesn't reliably turn on all GPIO clocks you need if you manually
  // set up pins in the configurator. So we'll configurate manually and turn
  // on all the clocks we need here.
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_RCC_HSEM_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOI_CLK_ENABLE();
  __HAL_RCC_GPIOJ_CLK_ENABLE();
  __HAL_RCC_GPIOK_CLK_ENABLE();
  __HAL_RCC_GPIOZ_CLK_ENABLE();
  {
    // Set up a test point so that we can use a voltmeter to manually verify we
    // get to the point of waiting for the A7 to send us a message over a RPMsg
    // channel later. The functions pinInit and pinSet are custom RTOS aware 
    // implementations that correctly handle all possible cases of hardware 
    // semaphore, FreeRTOS (pre and post init) and interrupts interacting with 
    // each other. 
    pinConfig_t pinConfig;
    pinConfig.alternate = 0;
    pinConfig.mode = pinOutputPushPull;
    pinConfig.pull = pinPullNone;
    pinConfig.speed = pinHighSpeed;
    pinInit(TEST_POINT_54_PORT,
        TEST_POINT_54_PIN,
        &pinConfig,
        false);
    pinSet(TEST_POINT_54_PORT,
        TEST_POINT_54_PIN,
        false);
  }
  /* USER CODE END Init */
 
  if(IS_ENGINEERING_BOOT_MODE())
  {
    /* Configure the system clock */
    // Note: Error handler is an infinite loop. Just here for now to verify this
    // isn't the code path we're following when testing RPMsg
    Error_Handler();
    SystemClock_Config();
  }
  else
  {
    /* IPCC initialisation */
    MX_IPCC_Init();
    /* OpenAmp initialisation ---------------------------------*/
    // Added error check, don't know why this isn't being checked 
    // normally by generated code...
    if (MX_OPENAMP_Init(RPMSG_REMOTE, NULL) != 0) { 
      Error_Handler();
    }
  }
 
  /* USER CODE BEGIN SysInit */
  if (!IS_ENGINEERING_BOOT_MODE()) {
    __enable_irq();
    initRPMsg();
// ... Program continues, but is not relevant to this question

Implementation of initRPMsg in uart.c:

/* RPMsg variables */
static uart_hardware_data_t virtualUart0 = {
    .VirtUartRxMsg = RESET,
    .VirtUartChannelBuffRx = {0},
    .VirtUartChannelRxSize = 0,
};
 
static uart_hardware_data_t virtualUart1 = {
    .VirtUartRxMsg = RESET,
    .VirtUartChannelBuffRx = {0},
    .VirtUartChannelRxSize = 0,
};
 
static uart_hardware_data_t virtualUart2 = {
    .VirtUartRxMsg = RESET,
    .VirtUartChannelBuffRx = {0},
    .VirtUartChannelRxSize = 0,
};
 
static uart_hardware_data_t virtualUart3 = {
    .VirtUartRxMsg = RESET,
    .VirtUartChannelBuffRx = {0},
    .VirtUartChannelRxSize = 0,
};
 
/* RPMsg callback prototypes, defined elsewhere */
static void VIRT_UART0_RxCpltCallback(VIRT_UART_HandleTypeDef *huart);
static void VIRT_UART1_RxCpltCallback(VIRT_UART_HandleTypeDef *huart);
static void VIRT_UART2_RxCpltCallback(VIRT_UART_HandleTypeDef *huart);
static void VIRT_UART3_RxCpltCallback(VIRT_UART_HandleTypeDef *huart);
 
 
////////////// INITILIZATION CODE //////////////
 
/*
 * open 4 virtual uart channels through rpmsg
 */
void initRPMsg()
{
  if (VIRT_UART_Init(&virtualUart0.handle) != VIRT_UART_OK) {
    Error_Handler();
  }
 
  if (VIRT_UART_Init(&virtualUart1.handle) != VIRT_UART_OK) {
    Error_Handler();
  }
 
  if (VIRT_UART_Init(&virtualUart2.handle) != VIRT_UART_OK) {
    Error_Handler();
  }
 
  if (VIRT_UART_Init(&virtualUart3.handle) != VIRT_UART_OK) {
    Error_Handler();
  }
 
  /*Need to register callback for message reception by channels*/
  if (VIRT_UART_RegisterCallback(&virtualUart0.handle, VIRT_UART_RXCPLT_CB_ID, VIRT_UART0_RxCpltCallback) != VIRT_UART_OK) {
    Error_Handler();
  }
  if (VIRT_UART_RegisterCallback(&virtualUart1.handle, VIRT_UART_RXCPLT_CB_ID, VIRT_UART1_RxCpltCallback) != VIRT_UART_OK) {
    Error_Handler();
  }
  if (VIRT_UART_RegisterCallback(&virtualUart2.handle, VIRT_UART_RXCPLT_CB_ID, VIRT_UART2_RxCpltCallback) != VIRT_UART_OK) {
    Error_Handler();
  }
  if (VIRT_UART_RegisterCallback(&virtualUart3.handle, VIRT_UART_RXCPLT_CB_ID, VIRT_UART3_RxCpltCallback) != VIRT_UART_OK) {
    Error_Handler();
  }
 
  // If we get here, then according to the SDK everything succeeded and
  // there SHOULD be ttyRPMSGX devices available in the linux /dev/ 
  // directory for the A7 application to grab.
  // I have verified using a voltmeter that this code does reach this point 
  // during execution, but the devices are not showing up in linux. 
  pinSet(TEST_POINT_54_PORT,
          TEST_POINT_54_PIN,
          true);
 
  // The A7 needs to send the first message on every channel to exchange 
  // buffer info, wait for that to happen in this defined order (checkUARTX 
  // just calls OPENAMP_check_for_message and then checks the handle's 
  // VirtUartRxMsg flag to see if a message has been received). It's OK that 
  // the order goes 1, 2, 3, 0, because that's the order we've implemented A7 
  // side. 
  while (checkUART1() == 0) {}
  while (checkUART2() == 0) {}
  while (checkUART3() == 0) {}
  while (checkUART0() == 0) {}

Any help would be appreciated, thanks!

Nathan

3 REPLIES 3
Erwan SZYMANSKI
ST Employee

Hello @NRoux.1​ ,

Regarding your issue, it is highly possible that you have a version alignment problem between your Cube_FW_Package version (that probably came with your upgrade of CubeIDE) and your OpenSTLinux version on A7 cortex side.

Please double check your versions on both side following information provided by the wiki here.

If you have a Cube_FW_Package v1.6, you need to have OSTL-4.1 in front of it with a kernel 5.15.

Kind regards,

Erwan.

In order 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.

Fair enough, I didn't realize that communication between the M4 and Linux isn't stable between versions and so you have to match them. Updating the Linux version probably isn't feasible for my project anymore, so I'll have to stick with the older version of the SDK and try to find a different solution to the issue I was trying to debug by updating SDK version (occasional dropped message from M4 to A7).

I guess I may as well ask about that directly then, are there any known reasons why an RP message sent by the M4 might not get received by the A7 (using ioctl and read) when in direct buffer mode, with no errors reported on either side? By that I mean I send a message from the M4 using VIRT_UART_Transmit and it returns VIRT_UART_OK, and then ioctl on the A7 doesn't report that data is available. It's pretty rare that this happens so retries work most of the time, but occasionally it fails 3 times in a row at which point my code calls it quits because at that point the underlying problem really needs to be addressed. The virtual uart interface I'm seeing the drops on is a command/response protocol so it's very low bandwidth, though I am also sending messages on other virtual uart interfaces as well (mostly debug logging messages) which are not synchronized to the main communication interface.

mschreiner
Associate

@Erwan SZYMANSKI I'm having same issues. Currently running 5.10.x Kernel and no chance to get the M4 communicating through RPMSG.

Do you have a changelog what had changed?

Do you have a list which FW package is compatible to which kernel version?