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.

CCS 6.1.1 and PRU v2.1.1 mixed language

I am learning the Beaglebone Black PRU tools and I would like to know if there are any examples of using mixed language C and assembly out there.

Currently I have a main.c with the entry point in C language.  I have an assembly module linked into my project with the .asm extension.  At the top of main.c I have an extern to an assembly function and I can successfully call and pass data and return data from the assembly function.

Most of the examples I've found are in pasm.  I am trying to learn from these examples and do it in CCS.

The big question I have is:

" Is there a way to replace the functionality of .setcallreg from pasm in the v2.1.1 compiler/assembler? "

I can do .macros but I would prefer to do calls with a return.  The .macros don't seem to play nice if they are nested.  I am working with the Blackhawk USB100v2 emulator.

Any pointers to more information would be much appreciated.

Thanks,

  • Hi,

    I will ask the PRU experts to comment. You can also check this thread: e2e.ti.com/.../491923
  • I almost figured it out.  I'm still clobbering my SPI_TX

    I just wanted to share what I learned.

    It's the JAL to the || label || command.

    Still need to protect the registers.

    Here is my main.c code:

    /*

    * main.c

    */

    #include <stdint.h>

    volatile register uint32_t __R30;

    volatile register uint32_t __R31;

     

     

    #define PRU0_PRU1_INTERRUPT (17)

    #define PRU1_PRU0_INTERRUPT (18)

    #define PRU0_ARM_INTERRUPT (19+16)

    #define PRU1_ARM_INTERRUPT (20+16)

     

    //extern uint32_t trySPI(uint32_t send_value); // assy function in gistfile1.asm

    extern void trySPI(uint32_t send_value); // assy function in gistfile1.asm

    extern void initIO(void); // assy function in gistfile1.asm

    volatile uint32_t send_value;

    int main(void) {

    initIO(); // make sure our IO levels are in the right state

    send_value = 0x00005c53;

    int count = 0;

    // uint32_t returned_value;

    // while (1)

    //{

    while (count < 64000)

    {

    // returned_value =

    trySPI(send_value); // call to assy lang to bit bang SPI

    __delay_cycles(20000);

    count++;

    }

    __delay_cycles(200000);

    send_value = 0x0000a55a;

    count = 0;

    while (count < 64000)

    {

    trySPI(send_value); // call to assy lang to bit bang SPI

    __delay_cycles(20000);

    count++;

    }

    __delay_cycles(200000);

    send_value = 0x00003333;

    count = 0;

    while (count < 64000)

    {

    trySPI(send_value); // call to assy lang to bit bang SPI

    __delay_cycles(20000);

    count++;

    }

    // }

     

     

     

    //; down here we send the PRU to ARM closing event then do a halt

    // now we can do the exit and halt

    __R31 = PRU0_ARM_INTERRUPT; //35; // here we notify the ARM we are ready to quit

     

    /* Halt the PRU core */

    __halt();

     

    return 0;

    }

    Here is the assembly:   not done yet but getting close.

     

     

    .asg "r4", SPI_TX ; these '.asg' are like the old defines in pasm

    .asg "r2", LS_RX

    .asg "r1", BIT ; don't mess with r3, we need this for the return

    .global dumbdelay ; needs to be here so the extern into C will work

    .align 4

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ; this is a countdown loop to slow things down so I can use my old scope to see things working

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    dumbdelay:

    ; LDI32 r5, 59

    LDI32 r5, 22

    REPEAT?: SUB r5, r5, 1

    QBNE REPEAT?, r5, 0

    JMP R3.w2;

     

    ;DUMBDELAY: .macro

    ;; LDI32 r5, 59

    ; LDI32 r5, 22

    ;REPEAT?: SUB r5, r5, 1

    ; QBNE REPEAT?, r5, 0

    ; .endm

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ; this does a single bit at a time, called 16 times from the send word macro below

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    .global spi_xfer_bit ; needs to be here so the extern into C will work

    .align 4

    spi_xfer_bit: ; .macro

    LDI32 r1, 0x00001eb0

    SBBO &r2, r1, 0, 48 ; save r2 through r13 at the start of this function

    ; DUMBDELAY ; slow things down

    JAL r3.w2, ||dumbdelay|| ; slow things down

    ; Output LSPD control

    QBBS MOSI_HIGH?, SPI_TX, BIT

    clr r30.w0, r30.w0, 1 ;// Clear bit 1 This is MOSI

    JMP MOSI_DONE?

    MOSI_HIGH?:

    set r30.w0, r30.w0, 1 ;// set bit 1 This is MOSI

    NOP

    MOSI_DONE?:

    clr r30.w0, r30.w0, 0 ;// clr bit 0 This is SPI_SCLK

    ; Read LSPD - Set b0 of R11 to MISO

    QBBC MISO_LOW?, R31.w0, 7 ; .asg This is MISO

    SET LS_RX, LS_RX, BIT

    JMP MISO_DONE?

    MISO_LOW?: ; labels inside macros need the '?' character to build

    NOP

    NOP

    MISO_DONE?:

    JAL r3.w2, ||dumbdelay|| ; slow things down

    set r30.w0, r30.w0, 0 ; set bit 0 This is SPI_SCLK

    NOP

    NOP

    LDI32 r1, 0x00001eb0

    LBBO &r2, r1, 0, 48 ; save r2 through r13 at the start of this function

    JMP R3.w2;

    ;.endm

     

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ; This macro calls the macro above for each bit

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    .global spi_xfer_word ; needs to be here so the extern into C will work

    .align 4

    spi_xfer_word: ;.macro

    LDI32 r1, 0x00001db0 ; some place in my memory, figure these locations later

    SBBO &r2, r1, 0, 48 ; save r2 through r13 at the start of this function

     

    LDI32 BIT, 15 ; this LDI command is 5ns long

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 14

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 13

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 12

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 11

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 10

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 9

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 8

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 7

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 6

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 5

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 4

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 3

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 2

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 1

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    LDI32 BIT, 0

    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    ; SPI_XFER_BIT

    ; .endm

    LDI32 r1, 0x00001db0

    LBBO &r2, r1, 0, 48 ; save r2 through r13 at the start of this function

    JMP R3.w2;

     

    .global trySPI ; needs to be here so the extern into C will work

    .align 4

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ; This is the function called from C code to send a word of data out SPI

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    trySPI:

    LDI32 r1, 0x00001fb0

    SBBO &r2, r1, 0, 48 ; save r2 through r13 at the start of this function

    mov SPI_TX, r0 ; r0 is the value passed in from C code

    LDI32 LS_RX, 0x00000000 ; clear input before we start to xmit This is r2

    clr r30.w0, r30.w0, 0 ; clr bit 0 This is SPI_SCLK P9.31

    NOP

    NOP

    ; NOP

    clr r30.w0, r30.w0, 2 ; clr bit 2 This is SYNC bit P9.30

    ; NOP

    ; NOP

    JAL r3.w2, ||spi_xfer_word|| ; call above function

    ; SPI_XFER_WORD ; here we bit bang through the macros above

    NOP

    NOP

    set r30.w0, r30.w0, 2 ; set bit 2 This is SYNC bit P9.30

    ; here we will try to return the LS_RX

    ; mov r1, LS_RX

    LDI32 r1, 0x00001fb0

    LBBO &r2, r1, 0, 48 ; restore r2 through r13 before we return to C code

    JMP R3.w2; ; this is like a return from the calling function

     

     

     

    .global initIO

    .align 4

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    ; This is the C function called from main at the start to set the SCLK, SYNC, and MOSI levels before we start

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    initIO:

    clr r30.w0, r30.w0, 1 ;// Clear bit 1 This is MOSI P9.29

    set r30.w0, r30.w0, 0 ; set bit 0 This is SPI_SCLK P9.31

    set r30.w0, r30.w0, 2 ; set bit 2 This is SYNC bit P9.30

    JMP R3.w2 ; this is like a return from the calling function

  • This is an improved version of the assembly in the previous reply.

    I fixed the SPI_TX and straightened up the save and reload of r2 thru r13 in the nested calls using r6 and r7.

    This works but not done by a long shot. My first stab at this had text.bin file of 1864 bytes using macros. By switching to function calls I'm down to 660 bytes of code.

    I just wanted to share. I haven't found much documentation or examples on this.

    .asg "r4", SPI_TX ; these '.asg' are like the old defines in pasm
    .asg "r2", LS_RX
    .asg "r1", BIT ; don't mess with r3, we need this for the return

    .global dumbdelay ; needs to be here so the extern into C will work
    .align 4

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; this is a countdown loop to slow things down so I can use my old scope to see things working
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    dumbdelay:
    LDI32 r5, 22
    REPEAT?: SUB r5, r5, 1
    QBNE REPEAT?, r5, 0
    JMP R3.w2;

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; this does a single bit at a time, called 16 times from the send word function below
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    .global spi_xfer_bit ; needs to be here so the extern into C will work
    .align 4

    spi_xfer_bit:
    LDI32 r7, 0x00001eb0
    SBBO &r2, r7, 0, 48 ; save r2 through r13 at the start of this function

    mov SPI_TX, r0 ; r0 is the value passed in from C code

    JAL r3.w2, ||dumbdelay|| ; slow things down
    ; Output LSPD control
    QBBS MOSI_HIGH?, SPI_TX, BIT
    clr r30.w0, r30.w0, 1 ;// Clear bit 1 This is MOSI
    JMP MOSI_DONE?
    MOSI_HIGH?:
    set r30.w0, r30.w0, 1 ;// set bit 1 This is MOSI
    NOP
    MOSI_DONE?:
    clr r30.w0, r30.w0, 0 ;// clr bit 0 This is SPI_SCLK

    ; Read LSPD - Set b0 of R11 to MISO
    QBBC MISO_LOW?, R31.w0, 7 ; .asg This is MISO
    SET LS_RX, LS_RX, BIT
    JMP MISO_DONE?
    MISO_LOW?: ; labels inside macros need the '?' character to build
    NOP
    NOP
    MISO_DONE?:
    JAL r3.w2, ||dumbdelay|| ; slow things down

    set r30.w0, r30.w0, 0 ; set bit 0 This is SPI_SCLK
    NOP
    NOP

    LDI32 r7, 0x00001eb0
    LBBO &r2, r7, 0, 48 ; reload r2 through r13 at the end of this function

    JMP R3.w2;

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; This function calls the function above for each bit
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    .global spi_xfer_word ; needs to be here so the extern into C will work
    .align 4

    spi_xfer_word:
    LDI32 r6, 0x00001db0 ; some place in my memory, figure these locations later
    SBBO &r2, r6, 0, 48 ; save r2 through r13 at the start of this function

    mov SPI_TX, r0 ; r0 is the value passed in from C code

    LDI32 BIT, 15 ; this LDI command is 5ns long
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 14
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 13
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 12
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 11
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 10
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 9
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 8
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 7
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 6
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 5
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 4
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 3
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 2
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 1
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 BIT, 0
    JAL r3.w2, ||spi_xfer_bit|| ; call above function

    LDI32 r6, 0x00001db0
    LBBO &r2, r6, 0, 48 ; reload r2 through r13 at the end of this function

    JMP R3.w2;


    .global trySPI ; needs to be here so the extern into C will work
    .align 4

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; This is the function called from C code to send a word of data out SPI
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    trySPI:
    LDI32 r1, 0x00001fb0
    SBBO &r2, r1, 0, 48 ; save r2 through r13 at the start of this function

    mov SPI_TX, r0 ; r0 is the value passed in from C code

    LDI32 LS_RX, 0x00000000 ; clear input before we start to xmit This is r2

    clr r30.w0, r30.w0, 0 ; clr bit 0 This is SPI_SCLK P9.31

    NOP
    NOP
    clr r30.w0, r30.w0, 2 ; clr bit 2 This is SYNC bit P9.30

    JAL r3.w2, ||spi_xfer_word|| ; call above function

    NOP
    NOP

    set r30.w0, r30.w0, 2 ; set bit 2 This is SYNC bit P9.30

    LDI32 r1, 0x00001fb0
    LBBO &r2, r1, 0, 48 ; restore r2 through r13 before we return to C code

    JMP R3.w2; ; this is like a return from the calling function


    .global initIO
    .align 4

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; This is the C function called from main at the start to set the SCLK, SYNC, and MOSI levels before we start
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    initIO:
    clr r30.w0, r30.w0, 1 ;// Clear bit 1 This is MOSI P9.29
    set r30.w0, r30.w0, 0 ; set bit 0 This is SPI_SCLK P9.31
    set r30.w0, r30.w0, 2 ; set bit 2 This is SYNC bit P9.30

    JMP R3.w2 ; this is like a return from the calling function