Tool/software: Linux
Hello,
First of all let me warn you that I am a complete newbie about working with the PRU and the BeagleBone, so I apologize if I am missing something obvious here.
For a school project, starting from the solution of the TI PRU Training Hands-on lab #5, I am trying to send messages from the PRU to the Linux host on the BeagleBoard as fast as possible. The idea would be to perform some audio processing on the PRU using inputs from microphones connected to the PRU and then send the resulting data to the host.
This is my code running on the PRU :
#include <stdint.h> #include <stdio.h> #include <pru_cfg.h> #include <pru_intc.h> #include <rsc_types.h> #include <pru_virtqueue.h> #include <pru_rpmsg.h> #include <time.h> #include "resource_table_1.h" volatile register uint32_t __R30; volatile register uint32_t __R31; /* Host-1 Interrupt sets bit 31 in register R31 */ #define HOST_INT ((uint32_t) 1 << 31) /* The PRU-ICSS system events used for RPMsg are defined in the Linux device tree * PRU0 uses system event 16 (To ARM) and 17 (From ARM) * PRU1 uses system event 18 (To ARM) and 19 (From ARM) */ #define TO_ARM_HOST 18 #define FROM_ARM_HOST 19 /* * Using the name 'rpmsg-pru' will probe the rpmsg_pru driver found * at linux-x.y.z/drivers/rpmsg/rpmsg_pru.c */ #define CHAN_NAME "rpmsg-pru" #define CHAN_DESC "Channel 31" #define CHAN_PORT 31 /* * Used to make sure the Linux drivers are ready for RPMsg communication * Found at linux-x.y.z/include/uapi/linux/virtio_config.h */ #define VIRTIO_CONFIG_S_DRIVER_OK 4 #define HEX_MASK 0xFF #define CLOCK_T_LEN sizeof(clock_t) uint8_t payload[RPMSG_BUF_SIZE]; size_t print_n_characters(size_t n, uint8_t * buffer) { if (n < 1) return 0; else if (n > 512) return 0; size_t i; for (i = 0; i < n-1; ++i) { buffer[i] = '0'; } buffer[n-1] = '\n'; return n; } void toggleLED() { __R30 ^= (1); } /* * main.c */ void main(void) { struct pru_rpmsg_transport transport; uint16_t src, dst, len; volatile uint8_t *status; /* allow OCP master port access by the PRU so the PRU can read external memories */ CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; /* clear the status of the PRU-ICSS system event that the ARM will use to 'kick' us */ CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST; /* Make sure the Linux drivers are ready for RPMsg communication */ status = &resourceTable.rpmsg_vdev.status; while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK)); /* Initialize pru_virtqueue corresponding to vring0 (PRU to ARM Host direction) */ pru_virtqueue_init(&transport.virtqueue0, &resourceTable.rpmsg_vring0, TO_ARM_HOST, FROM_ARM_HOST); /* Initialize pru_virtqueue corresponding to vring1 (ARM Host to PRU direction) */ pru_virtqueue_init(&transport.virtqueue1, &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST); /* Create the RPMsg channel between the PRU and ARM user space using the transport structure. */ while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS); while (1) { /* Check bit 30 of register R31 to see if the ARM has kicked us */ if (__R31 & HOST_INT) { /* Clear the event status */ CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST; /* Receive all available messages, multiple messages can be sent per kick */ while (pru_rpmsg_receive(&transport, &src, &dst, payload, &len) == PRU_RPMSG_SUCCESS) { /* Call ctime several times to check the number of cycles it takes for it to be sent. */ #define TEXT "Transmitting 100 messages almost as fast as possible :\n" char msg1[] = TEXT; pru_rpmsg_send(&transport, dst, src, msg1, sizeof(TEXT)); #undef TEXT clock_t i; len = print_n_characters(400, payload); for (i = 0; i < 100; ++i) { // Wait for a buffer to be available while(pru_rpmsg_send(&transport, dst, src, payload, len) != PRU_RPMSG_SUCCESS); //__delay_cycles(30000); } #define TEXT "Transmission ended successfully." char msg2[] = TEXT; pru_rpmsg_send(&transport, dst, src, msg2, sizeof(TEXT)); #undef TEXT } } } }
I have not written any code running on the host side. I simply do echo S > /dev/rpmsg_pru31 && cat /dev/rpmsg_pru31.
If I do not set any significant delay between each call to pru_rpmsg_send() (about 500 000 cycles), I get tons of the following error messages in dmesg on the host side :
[ +0.005616] rpmsg_pru rpmsg36: Message length table is full
And the program on the PRU hangs. If the delay is high enough though, all messages get sent successfully and without error.
Could this be an error in my code ? I am very new to the BeagleBone, the PRU, and embedded programming in general, I am doing this for a school project.
I noticed someone had a quite similar issue and he got answers saying this was a bug in the pru_rpmsg_virtqueue.h file which has since been fixed in the pru-software-support-package (see this post: ) but the problem persists.
Feel free to ask for more information if needed.
Regards,
Loïc