STM32MP1 RPMsg doesn't create channels after updating CubeMX and CubeIDE to latest versions
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 questionImplementation 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
