This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Seems like this is a pretty common issue. I have been wading through the info and haven't found a clear answer.
The TRM table 9-80 list interrupts for ICSSG as 120-127 and 248-255;
Interrupt Input Line Interrupt ID Source Interrupt
R5FSS0_CORE0_INTR_IN_120 120 PRU_ICSSG0_PR1_HOST_INTR_PEND_0
R5FSS0_CORE0_INTR_IN_121 121 PRU_ICSSG0_PR1_HOST_INTR_PEND_1
R5FSS0_CORE0_INTR_IN_122 122 PRU_ICSSG0_PR1_HOST_INTR_PEND_2
R5FSS0_CORE0_INTR_IN_123 123 PRU_ICSSG0_PR1_HOST_INTR_PEND_3
R5FSS0_CORE0_INTR_IN_124 124 PRU_ICSSG0_PR1_HOST_INTR_PEND_4
R5FSS0_CORE0_INTR_IN_125 125 PRU_ICSSG0_PR1_HOST_INTR_PEND_5
R5FSS0_CORE0_INTR_IN_126 126 PRU_ICSSG0_PR1_HOST_INTR_PEND_6
R5FSS0_CORE0_INTR_IN_127 127 PRU_ICSSG0_PR1_HOST_INTR_PEND_7
R5FSS0_CORE0_INTR_IN_248 248 PRU_ICSSG1_PR1_HOST_INTR_PEND_0
R5FSS0_CORE0_INTR_IN_249 249 PRU_ICSSG1_PR1_HOST_INTR_PEND_1
R5FSS0_CORE0_INTR_IN_250 250 PRU_ICSSG1_PR1_HOST_INTR_PEND_2
R5FSS0_CORE0_INTR_IN_251 251 PRU_ICSSG1_PR1_HOST_INTR_PEND_3
R5FSS0_CORE0_INTR_IN_252 252 PRU_ICSSG1_PR1_HOST_INTR_PEND_4
R5FSS0_CORE0_INTR_IN_253 253 PRU_ICSSG1_PR1_HOST_INTR_PEND_5
R5FSS0_CORE0_INTR_IN_254 254 PRU_ICSSG1_PR1_HOST_INTR_PEND_6
R5FSS0_CORE0_INTR_IN_255 255 PRU_ICSSG1_PR1_HOST_INTR_PEND_7
There does not appear to be any cross reference to to how these relate to the PRU pr<k>_pru_mst_intr[15:0]_intr_req
The info on generating the PRU interrupt is well written and easy to understand. Receiving the interrupt on the R5F cores is not clear.
From the info and examples in the mcu_plus_sdk_am64x_08_05_00_24 it appears the proper mechanism is to use the HwiP_xxx interface.
However I have not had much luck.
My code on R5 looks something like this.
HwiP_Object HwiObject;
HwiP_Params hwiPrms;
HwiP_init();
HwiP_Params_init(&hwiPrms);
hwiPrms.intNum = intNum;
hwiPrms.callback = IsrFxn;
hwiPrms.args = (void *) intNum;
retVal = HwiP_construct(&HwiObject, &hwiPrms);
any help getting this to work would be greatly appreciated. Currently I am just building a generic example.
I would be happy to share it with the community once I have it resolved.
I used a brute force approach to find a basic set PRU / R5 files that "work". I am sure I need to make adjustments to PRU code to get additional channels operational.
The code is based on two examples;
1. from the PRU software support package
examples/am64x/PRU_RPMsg_Echo_Interrupt1
I gutted the RPMsg demo file to create this:
#include <stdio.h> #include <pru_intc.h> #include "resource_table.h" #include "intc_map_1.h" volatile register uint32_t __R31; #define R5_INT_249_CHANNEL 0x02 #define INT_ENABLE (1 << 5) /* * main.c */ void main(void) { CT_INTC.ENABLE_SET_INDEX_REG_bit.ENABLE_SET_INDEX |= (1 << 2); CT_INTC.HINT_ENABLE_SET_INDEX_REG_bit.HINT_ENABLE_SET_INDEX |= (1 << 2); CT_INTC.GLOBAL_ENABLE_HINT_REG_bit.ENABLE_HINT_ANY = 1; while (1) { __R31 = INT_ENABLE|R5_INT_249_CHANNEL; __delay_cycles(200000000*10); } }
2. from mcu_plus_sdk_am64x_08_05_00_24
./examples/motor_control/benchmark_demo/am64x-evm/r5fss0-0_nortos/ti-arm-clang/
I gutted /examples/motor_control/benchmark_demo/am64x-evm/r5fss0-0_nortos/main.c to create this:
#include <stdlib.h> #include "ti_drivers_config.h" #include "ti_board_config.h" #include "ti_drivers_open_close.h" #include "benchmarkdemo.h" volatile uint32_t intEvent = 0UL; volatile uint32_t intCapt = 0; volatile uint32_t intNum = 0UL; HwiP_Object HwiObject; static void IsrFxn(void *args) { intNum = (uint32_t)args; intEvent++; intCapt++; HwiP_clearInt(intNum); } int main(void) { HwiP_Params hwiPrms; uint32_t intNum = 249; int32_t retVal; System_init(); Board_init(); Drivers_open(); DebugP_log("\r\nSTART INTC test App\r\n"); HwiP_init(); DebugP_log("HWI START\n"); hwiPrms.intNum = intNum; hwiPrms.callback = IsrFxn; hwiPrms.args = (void *)intNum; retVal = HwiP_construct(&HwiObject, &hwiPrms); DebugP_assert(retVal == SystemP_SUCCESS); DebugP_log("Interrupt 249 initialized\n"); HwiP_enable(); DebugP_log("HWI Enabled\n"); while(1) { if(intCapt != 0) { intCapt = 0; { DebugP_log("interrupt 249 received %d times\n", intEvent); } } } Drivers_close(); Board_deinit(); System_deinit(); return 0; }
Things I am not totally clear on;
registers to initialize in PRU to change mapping to R5F interrupts.
is the register range in R5 table 9-80 120-127 for PRU0 and 248-255 for PRU1
do these register ranges map to the 8 PRU event channels 2-9 as stated in section 6.4.7.1
"Host Interrupts 2 through 9 exported from PRU_ICSSG and mapped to device level interrupt controllers."
I hope a TI expert can help me clean this up and get clarification for register setup in PRU code and clean up on the R5 code.
Hi,
1.
registers to initialize in PRU to change mapping to R5F interrupts.
From AM64x TRM 6.4.5.2.2.2:
Simultaneously writing a ‘1’ to pru_r31_vec_valid (R31 bit 5) and a channel number from 0 to 15 to pru_r31_vec[3:0] (R31 bits 3-0) creates a pulse on the output of the corresponding pr_pru_mst_intr[x]_intr_req INTC system event. For example, writing ‘100000’ will generate a pulse on prk_pru_mst_intr[0]_intr_req, writing ‘100001’ will generate a pulse on prk_pru_mst_intr[1]_intr_req, and so on to where writing ‘101111’ will generate a pulse on prk_pru_mst_intr[15]_intr_req and writing ‘0xxxxx’ will not generate any system event pulses.
The output values from both PRU cores in a subsystem are ORed together. The output channels 0-15 are connected to the INTC system events 16-31, respectively. This allows the PRU to assert one of the system events 16-31 by writing to its own R31 register. The host to be signaled is determined by the system interrupt to interrupt channel mapping (programmable).
2.
is the register range in R5 table 9-80 120-127 for PRU0 and 248-255 for PRU1
The interrupt ID 120-127 refer to ICSSG0 interrupts and 248-255 refer to ICSSG1 interrupts.
3.
do these register ranges map to the 8 PRU event channels 2-9 as stated in section 6.4.7.1
Host interrupts 2 through 9 are exported to system interrupts and correspond to PRU_ICSSG0_PR1_HOST_INTR_PEND_0 through PRU_ICSSG0_PR1_HOST_INTR_PEND_7 and create interrupt on R5F0-0 on input interrupt lines 120-127.
Additionally, I would suggest you use Sysconfig to configure the interrupt settings and utilize the existing IPC APIs (AM64x MCU+ SDK: PRU IPC (ti.com)) for easier development.
You can also refer to the PRU-ADC interfacing examples in the SDK, it has sample transfer from PRU to R5F (to TCM) using the PRU IPC APIs.
Do let me know if you have any more questions.
Regards,
Nitika
In the above PRU example code i am running on ICSSG1_PRU1 and triggering prk_pru_mst_intr[2]_intr_req. This is received as interrupt 249 i.e.R5FSS0_CORE0_INTR_IN_249 PRU_ICSSG1_PR1_HOST_INTR_PEND_1 on R5F0-0.
it is not clear how prk_pru_mst_intr[X]_intr_req maps to PRU_ICSSG1_PR1_HOST_INTR_PEND_X
How would I modify the existing example code to trigger interrupt 250 PRU_ICSSG1_PR1_HOST_INTR_PEND_2?
The R5F code appears to be correct for receiving this interrupt. In theory I would only need to change the R5F intNum = 250;
what would I need to change in the PRU1_1 code?
specifically;
what values would I write to these registers;
CT_INTC.ENABLE_SET_INDEX_REG_bit.ENABLE_SET_INDEX
CT_INTC.HINT_ENABLE_SET_INDEX_REG_bit.HINT_ENABLE_SET_INDEX
Which channel map register CH_MAP_REGx would I configure and which prk_pru_mst_intr[X]_intr_req would I write to trigger the interrupt?
Hi,
The prk_pru_mst_intr[x]_intr_req does not map directly to PRU_ICSSG1_PR1_HOST_INTR_PEND_X. prk_pru_mst_intr[0:15]_intr_req signals map to system events 16-31, respectively (similarly, host interrupts 2-9 correspond to PRU_ICSSG1_PR1_HOST_INTR_PEND_0-7 and create interrupt on interrupt lines 248-255).
From there, the host to be signaled is determined by the system interrupt to interrupt channel mapping (programmable) and the interrupt channel to host interrupt mapping.
1.
what values would I write to these registers;
CT_INTC.ENABLE_SET_INDEX_REG_bit.ENABLE_SET_INDEX
CT_INTC.HINT_ENABLE_SET_INDEX_REG_bit.HINT_ENABLE_SET_INDEX
To trigger interrupt 250, PRU_ICSSG1_PR1_HOST_INTR_PEND_2, we select host interrupt 4 and channel 4 (recommended to map channel “x” to host interrupt “x”) and set the 4th bit in the above registers as below:
CT_INTC.ENABLE_SET_INDEX_REG_bit.ENABLE_SET_INDEX |= (1 << 4); CT_INTC.HINT_ENABLE_SET_INDEX_REG_bit.HINT_ENABLE_SET_INDEX |= (1 << 4);
2.
Which channel map register CH_MAP_REGx would I configure and which prk_pru_mst_intr[X]_intr_req would I write to trigger the interrupt?
Channel map registers (CH_MAP_REGx, x=0 to 39) define the channel for each interrupt. There is one register per 4 interrupts, so 40 channel map registers for all 160 interrupts (see Table 6-975 of TRM). So, CH_MAP_REG4 is the channel map register for system events 16 to 19 (prk_pru_mst_intr[0-3]_intr_req).
To map interrupt signal prk_pru_mst_intr[0]_intr_reg (system event 16) to interrupt channel 4, we write 0x4 in CH_MAP_16 bits of the above register.
Generating interrupt from PRU:
Writing ‘1’ to pru_r31_vec_valid (R31 bit 5) and a channel number from 0 to 15 to pru_r31_vec[3:0] (R31 bits 3-0) creates a pulse on the output of the corresponding pr_pru_mst_intr[x]_intr_req INTC system event. Writing ‘100000’ will generate a pulse on prk_pru_mst_intr[0]_intr_req (event number 16, from TRM Table 6-522). See section 6.4.5.2.2.2 from the TRM for more details.
Do let me know if this helps your solution.
Regards,
Nitika
Nitika,
Thank you for the thorough explanation. However, I have tried this modification and do not get an interrupt. I ran some more tests and found the default power on configuration of ICSSG1_PRU1 will trigger interrupt 249, PRU_ICSSG1_PR1_HOST_INTR_PEND_1, whenever prk_pru_mst_intr[2]_intr_req is asserted.
i.e. writing ((1 << 5) | 2) to register __R31.
I am using SK-AM64b starter kit to perform prototype testing. I have used the example programs mentioned above. I need to reliably trigger a single interrupt on each of the four R5 cores. So I will need to trigger any of 4 of the 8 interrupts available on the R5s
I am using mcu_plus_sdk_am64x_08_05_00_24 and (PRU) Software Support Package v6.1.0
I assume I have a fundamental misunderstanding of the PRU configuration. It is also possible the R5 API usage is wrong.
Any assistance you can provide to get this working is greatly appreciated.
Hi,
There seems to be an issue with the R5F code and some missing configuration on the PRU side.
Allow me some time to go through your implementation and I'll get back to you.
Regards,
Nitika.
I created this script to make it easier to start, stop, and query trace file for remote processors. might be helpful for other than don't want to do all the extra typing. This has been ported from am5729 to work with am6442 on SK-am64b starter kit
the file failed to attach. Linux script source here
PROC=7 usage() { printf "\nUsage: rp <args> \n\t stat - show remote processors status\n\t temp - show processor temps\n\t start <cpu#> - start remote processor\n\t stop <cpu#> - stop remote processor\n\t halt <cpu#> - suspend current processor (not supported on some procs)\n" } start() { local var="/sys/class/remoteproc/remoteproc$PROC/state" echo $var echo start > $var } stop() { local var="/sys/class/remoteproc/remoteproc$PROC/state" echo stop > $var } halt() { local var="/sys/class/remoteproc/remoteproc$PROC/state" echo halt > $var } stat() { for F in /sys/class/remoteproc/remoteproc* do printf '%s\t%s\t%s\n' `echo $F |cut -d'/' -f5 | tr -d '\n'` `cat $F/name |cut -d '.' -f2 |tr -d '\n'` `cat $F/state` done |sort -V | grep -vE 'tx|rt' } temp() { local ztype=`cat /sys/devices/virtual/thermal/thermal_zone0/type` local ztemp=`cat /sys/devices/virtual/thermal/thermal_zone0/temp` local val=$((ztemp/1000)) local frac=$((ztemp-(val*1000))) printf "%s\t %d.%d C\n" $ztype $val $frac ztype=`cat /sys/devices/virtual/thermal/thermal_zone1/type` ztemp=`cat /sys/devices/virtual/thermal/thermal_zone1/temp` local val=$((ztemp/1000)) local frac=$((ztemp-(val*1000))) printf "%s\t %d.%d\tC\n" $ztype $val $frac } trace() { local filename="/sys/kernel/debug/remoteproc/remoteproc$PROC/trace0" if sudo test -f $filename then sudo cat $filename else printf "no trace file found for remote processor %d\n" $PROC fi } PROC=$2 case "$1" in '-h') usage ;; '') usage ;; 'trace') if [[ $# -eq 2 ]] then trace else usage fi ;; 'stat') stat ;; 'start') if [[ $# -eq 2 ]] then start else usage fi ;; 'stop') if [[ $# -eq 2 ]] then stop else usage fi ;; 'temp') temp ;; 'halt') if [[ $# -eq 2 ]] then stop else usage fi ;; *) usage ;; esac
Hi,
Thank you for the script, I hope it will be helpful for others.
Regarding the interrupt generation, there are a few steps missing in your implementation. The TRM lists down the steps required for interrupt configuration as below:
You can find all these steps implemented in the PRUICSS_intcInit function at mcu_plus_sdk_am64x\source\drivers\pruicss\g_v0, the API is implemented in the PRU ADC example (mcu_plus_sdk_am64x\examples\pru_io\adc\ads127\ads127_example.c) to create interrupts between R5F and PRU.
The above implementation uses sysconfig interface to select the channel and host interrupt, auto-generated file ti_driver_config.c consists of the structures used by the above function.
Can you please let me know if you are still facing the issue in generating the PRU to R5F interrupts?
Regards,
Nitika.
Sorry for the late reply, been out of country for last couple weeks. I did find the files you point to and with the previous info you provided I was able to work out the details. PRU code below;
#include <stdint.h> #include <stdio.h> #include <string.h> #include <pru_intc.h> #include "resource_table.h" #include "intc_map_1.h" volatile register uint32_t __R31; #define R5_INTR_248 2 #define R5_INTR_249 3 #define R5_INTR_250 4 #define R5_INTR_251 5 #define R5_INTR_252 6 #define R5_INTR_253 7 #define R5_INTR_254 8 #define R5_INTR_255 9 #define HOST_INT 2 #define INT_ENABLE (1 << 5) void main(void) { // // set the interrupt polarity // // active high is the default (1); // events 2-9 are .POLARITY_66-73 // set to (0) for active low // CT_INTC.POLARITY_REG2_bit.POLARITY_XX = 0; // // set interrupt type (PULSE, LEVEL) // default (0) = LEVEL // set to 1 for PULSE // CT_INTC.TYPE_REG2_bit.TYPE_XX = 0; // // clear interrupt status register for intr # // CT_INTC.STATUS_CLR_INDEX_REG_bit.STATUS_CLR_INDEX = R5_INTR_255; // // enable desired intr # // CT_INTC.ENABLE_SET_INDEX_REG_bit.ENABLE_SET_INDEX = R5_INTR_255; CT_INTC.HINT_ENABLE_SET_INDEX_REG_bit.HINT_ENABLE_SET_INDEX = R5_INTR_255; // // map channel to host interrupt // CT_INTC.HINT_MAP_REG0_bit.HINT_MAP_3 = R5_INTR_255; // // map event to channel // CT_INTC.CH_MAP_REG4_bit.CH_MAP_16 = R5_INTR_255; // // enable global interrupts // CT_INTC.GLOBAL_ENABLE_HINT_REG_bit.ENABLE_HINT_ANY = 1; while (1) { __delay_cycles((uint32_t)(200000000UL*10UL)); __R31 = INT_ENABLE|HOST_INT; } }
The R5F code works as expected and no changes were needed. The hwiPrms.intNum parameter just needs to match the interrupt number selected in the PRU code.
e.g.
hwiPrms.intNum = 248;