This is bizarre.
AM3359
Code running on PRU1
Code compiled with PRU C Compiler 2.1 and CCSV6.0.1.00040
Synopsis: I have some inline code that toggles an I/O line a certain number of times with some delays between high to low and low to high so I can see what is happening on a scope. This all works EXCEPT that some of the code gets skipped. I varied the timing of the transitions so that I can tell which sections of code are getting skipped. Here is the code:
#include <stdint.h> #include <pru_cfg.h> #include "resource_table_1.h" volatile register uint32_t __R30; volatile register uint32_t __R31; #define INVERT 1 #define JBUS_TX 0x100 // Pin 8 of register R30, maps to GPIO 2-22 #define BIT_TIME 20832 // 104.16 microseconds at 200 Mhz = 9600 baud #define BIT_TIME2 20832*2 // 104.16 microseconds at 200 Mhz = 9600 baud #define BIT_TIME3 20832*3 // 104.16 microseconds at 200 Mhz = 9600 baud #define BIT_TIME4 20832*4 // 104.16 microseconds at 200 Mhz = 9600 baud #define BIT_TIME5 20832*5 // 104.16 microseconds at 200 Mhz = 9600 baud #define HALF_SEC 100000000 // half a second at 200 Mhz #define H100_MSEC 20000000 // 100 milliseconds #if INVERT #define SET_HIGH {gpo |= JBUS_TX; __R30 = gpo;} #define SET_LOW {gpo &= ~JBUS_TX; __R30 = gpo;} #else #define SET_HIGH {gpo &= ~JBUS_TX; __R30 = gpo;} #define SET_LOW {gpo |= JBUS_TX; __R30 = gpo;} #endif unsigned int i; unsigned char c; uint32_t gpo; void main() { gpo = __R30; /* Set JBUS TX high to start (bus idle state) */ SET_HIGH; __delay_cycles(HALF_SEC); /* TEST */ while(1) { // start bit SET_LOW; __delay_cycles(BIT_TIME); SET_HIGH; __delay_cycles(BIT_TIME); SET_LOW; __delay_cycles(BIT_TIME5); SET_HIGH; __delay_cycles(BIT_TIME); SET_LOW; __delay_cycles(BIT_TIME4); SET_HIGH; __delay_cycles(BIT_TIME); SET_LOW; __delay_cycles(BIT_TIME3); SET_HIGH; __delay_cycles(BIT_TIME); SET_LOW; __delay_cycles(BIT_TIME2); SET_HIGH; __delay_cycles(BIT_TIME); SET_LOW; __delay_cycles(BIT_TIME3); // stop bit SET_HIGH; __delay_cycles(BIT_TIME); __delay_cycles(H100_MSEC); } }
This should cause a series of transitions where all high bits are one bit time (104.16 usec). The low bits should be in the sequence of 1,5,4,3,2,3 bit times. What happens is that I get low, high, 5xlow,high,4xlow. All good so far. But then I get a 2x high. The 1xhigh and 3xlow have been skipped. Then its all good again. I get 2xlow, 1xhigh, 3xlow, and the stop bit of 1xhigh.
I have looked at the generated assembler code and it all seems OK although I am not that familiar with this assembler. The code for the missing transitions seems to be there. What is odd is that every label for a QBNE statement to jump to is $1. But there is always a .newblock directive which I assume causes the assembler to be able to work out which $1 is which. Here is the part of the code that gets skipped.
;---------------------------------------------------------------------- ; 60 | __delay_cycles(BIT_TIME); ;---------------------------------------------------------------------- .newblock LDI32 r19, 10415 $1: SUB r19, r19, 1 QBNE $1, r19, 0 ; [ALU_PRU] |60| NOP ; [ALU_PRU] .dwpsn file "../main.c",line 61,column 2,is_stmt,isa 0 ;---------------------------------------------------------------------- ; 61 | SET_LOW; ;---------------------------------------------------------------------- LBBO &r19, r0, 0, 4 ; [ALU_PRU] |61| CLR r19, r19, 0x00000008 ; [ALU_PRU] |61| SBBO &r19, r0, 0, 4 ; [ALU_PRU] |61| LBBO &r30, r0, 0, 4 ; [ALU_PRU] |61| .dwpsn file "../main.c",line 62,column 2,is_stmt,isa 0 ;---------------------------------------------------------------------- ; 62 | __delay_cycles(BIT_TIME3); ;---------------------------------------------------------------------- .newblock LDI32 r18, 31247 $1: SUB r18, r18, 1 QBNE $1, r18, 0 ; [ALU_PRU] |62| NOP ; [ALU_PRU] .dwpsn file "../main.c",line 64,column 2,is_stmt,isa 0 ;---------------------------------------------------------------------- ; 64 | SET_HIGH; ;---------------------------------------------------------------------- LBBO &r18, r0, 0, 4 ; [ALU_PRU] |64| SET r18, r18, 0x00000008 ; [ALU_PRU] |64| SBBO &r18, r0, 0, 4 ; [ALU_PRU] |64| LBBO &r30, r0, 0, 4 ; [ALU_PRU] |64| .dwpsn file "../main.c",line 65,column 2,is_stmt,isa 0 ;---------------------------------------------------------------------- ; 65 | __delay_cycles(BIT_TIME); ;---------------------------------------------------------------------- .newblock LDI32 r17, 10415 $1: SUB r17, r17, 1 QBNE $1, r17, 0 ; [ALU_PRU] |65| NOP ; [ALU_PRU] .dwpsn file "../main.c",line 66,column 2,is_stmt,isa 0 ;---------------------------------------------------------------------- ; 66 | SET_LOW; ;---------------------------------------------------------------------- LBBO &r17, r0, 0, 4 ; [ALU_PRU] |66| CLR r17, r17, 0x00000008 ; [ALU_PRU] |66| SBBO &r17, r0, 0, 4 ; [ALU_PRU] |66| LBBO &r30, r0, 0, 4 ; [ALU_PRU] |66| .dwpsn file "../main.c",line 67,column 2,is_stmt,isa 0 ;---------------------------------------------------------------------- ; 67 | __delay_cycles(BIT_TIME2); ;---------------------------------------------------------------------- .newblock LDI32 r16, 20831 $1: SUB r16, r16, 1 QBNE $1, r16, 0 ; [ALU_PRU] |67| NOP ; [ALU_PRU] .dwpsn file "../main.c",line 69,column 2,is_stmt,isa 0
One other clue. I wondered if this problem is position dependent and it does seem to be. The code that gets skipped isn't dependent on what that code happens to do.
There are other bizarre things that happen here that really make me wonder about this C compiler. For instance for loops don't seem to work but a functionally identical while loop does work.
But lets start with this problem. Can anyone suggest what might be wrong here?