Bare metal audio output on Raspberry Pi3 working in AARCH64 asm but not the C version

1

I have been trying to write a bare metal kernel for over a year now and I am up to the point where I am ready to start working on audio output. I have written the code in asm however since I'm not great at it I'm not sure how I can pass audio samples as arguments to a asm function. I tried to rewrite it in C however it isn't working. This problem is really a spot the difference. I know my asm version works but the audio sample is written into the play_audio function. My goal is to have a init function for the audio with no arguments and a play_audio function that takes the pointer to the start of the audio function and a pointer to the end of the audio file. The audio file to be played is a 16 bit unsigned int pcm file. The same file that I'm trying to use for the C audio part is used successfully in the asm version. Since I set the hardware pwm to expect 13bit audio at 41400Hz there is a shift to convert the sample from 16bit to 13 bit so this isn't a mistake.

Not_working_audio.c

void init_audio_jack_c()//ERROR IN HERE
{
    //Set phone jack to pwm output
    uint32_t *gpio_addr = (uint32_t *)(PERIPHERAL_BASE + GPIO_BASE);
    uint32_t *gpio_gpfsel4_addr = gpio_addr + GPIO_GPFSEL4;
    *gpio_gpfsel4_addr = GPIO_FSEL0_ALT0 | GPIO_FSEL5_ALT0;

    //Set clock
    uint32_t *clock_manager_addr = (uint32_t *)(((PERIPHERAL_BASE + CM_BASE) & 0x0000FFFF) | ((PERIPHERAL_BASE + CM_BASE) & 0xFFFF0000));
    *(clock_manager_addr + CM_PWMDIV) = (CM_PASSWORD | 0x2000);

    *(clock_manager_addr + CM_PWMCTL) = ((CM_PASSWORD | CM_ENAB) | (CM_SRC_OSCILLATOR + CM_SRC_PLLCPER));

    //Set PWM
    uint32_t *pwm_manager_addr = (uint32_t *)(((PERIPHERAL_BASE + PWM_BASE) & 0x0000FFFF) | ((PERIPHERAL_BASE + PWM_BASE) & 0xFFFF0000));
    *(pwm_manager_addr + PWM_RNG1) = 0x1624;
    *(pwm_manager_addr + PWM_RNG2) = 0x1624;

    *(pwm_manager_addr + PWM_CTL) = PWM_USEF2 + PWM_PWEN2 + PWM_USEF1 + PWM_PWEN1 + PWM_CLRF1;

    printf("[INFO] Audio Init Finished");
}


int32_t play_16bit_unsigned_audio(uint16_t *start, uint16_t *end)
{
    if(end < start) 
    {
        printf("[ERROR] End is less than start.");
        return 1;
    }
    if((start - end) % 2 == 0)
    {
        printf("[ERROR] Isn't a multiple of two so it isn't 16bit");
        return 2;
    }

    uint16_t *end_of_file = (uint16_t *)(uint64_t)(((uint32_t)(uintptr_t)end & 0x0000FFFF) | ((uint32_t)(uintptr_t)end & 0xFFFF0000));

    //FIFO write
    while(start != end_of_file)
    {
        uint16_t sample = start[0];
        sample >>= 3;
        *(uint32_t *)((((uint32_t)(PERIPHERAL_BASE + PWM_BASE) & 0x0000FFFF) | ((uint32_t)(PERIPHERAL_BASE + PWM_BASE) & 0xFFFF0000)) + PWM_FIF1) = sample;

        start++;
        sample = start[0];
        sample >>= 3;
        *(uint32_t *)((((uint32_t)(PERIPHERAL_BASE + PWM_BASE) & 0x0000FFFF) | ((uint32_t)(PERIPHERAL_BASE + PWM_BASE) & 0xFFFF0000)) + PWM_FIF1) = sample;

        //FIFO wait
        while(*(uint32_t *)((((uint32_t)(PERIPHERAL_BASE + PWM_BASE) & 0x0000FFFF) | ((uint32_t)(PERIPHERAL_BASE + PWM_BASE) & 0xFFFF0000)) + PWM_STA) != PWM_FULL1);
        start++;
    }
    printf("[INFO] Completed Audio");
    return 0;
}

Working_audio.s

.section .text.init_audio_jack, "ax", %progbits
.balign 4
.globl init_audio_jack;
.type init_audio_jack, %function
init_audio_jack:
    mov w0,PERIPHERAL_BASE + GPIO_BASE
    mov w1,GPIO_FSEL0_ALT0
    orr w1,w1,GPIO_FSEL5_ALT0
    str w1,[x0,GPIO_GPFSEL4]

    // Set Clock
    mov w0, PERIPHERAL_BASE
    add w0, w0, CM_BASE
    and w0, w0, 0x0000FFFF

    mov w1, PERIPHERAL_BASE 
    add w1, w1, CM_BASE
    and w1, w1, 0xFFFF0000

    orr w0,w0,w1
    mov w1,CM_PASSWORD
    orr w1,w1,0x2000 // Bits 0..11 Fractional Part Of Divisor = 0, Bits 12..23 Integer Part Of Divisor = 2
    brk #0
    str w1,[x0,CM_PWMDIV]

    mov w1,CM_PASSWORD
    orr w1,w1,CM_ENAB
    orr w1,w1,CM_SRC_OSCILLATOR + CM_SRC_PLLCPER // Use 650MHz PLLC Clock
    str w1,[x0,CM_PWMCTL]

    // Set PWM
    mov w0, PERIPHERAL_BASE
    add w0, w0, PWM_BASE
    and w0, w0, 0x0000FFFF

    mov w1,PERIPHERAL_BASE
    add w1, w1, PWM_BASE
    and w1, w1, 0xFFFF0000

    orr w0,w0,w1
    mov w1,0x1624 // Range = 13bit 44100Hz Mono
    str w1,[x0,PWM_RNG1]
    str w1,[x0,PWM_RNG2]

    mov w1,PWM_USEF2 + PWM_PWEN2 + PWM_USEF1 + PWM_PWEN1 + PWM_CLRF1
    str w1,[x0,PWM_CTL]


.section .text.play_audio, "ax", %progbits
.balign 4
.globl play_audio;
.type play_audio, %function
play_audio:
    Loop:
        adr x1, _binary_src_audio_Interlude_bin_start // X1 = Sound Sample
        ldr w2, =_binary_src_audio_Interlude_bin_end
        and w2, w2, 0x0000FFFF // W2 = End Of Sound Sample
        ldr w3, =_binary_src_audio_Interlude_bin_end
        and w3, w3, 0xFFFF0000
        orr w2,w2,w3
        FIFO_Write:
            ldrh w3,[x1],2 // Write 2 Bytes To FIFO
            lsr w3,w3,3 // Convert 16bit To 13bit
            str w3,[x0,PWM_FIF1] // FIFO Address

            ldrh w3, [x1], 2
            lsr w3, w3, 3
            str w3, [x0, PWM_FIF1]
        FIFO_Wait:
            ldr w3,[x0,PWM_STA]
            tst w3,PWM_FULL1 // Test Bit 1 FIFO Full
            b.ne FIFO_Wait
        cmp w1,w2 // Check End Of Sound Sample
        b.ne FIFO_Write
    b Loop // Play Sample Again

Thanks in advance to anyone that can help!

c
assembly
raspberry-pi3
arm64
bare-metal
asked on Stack Overflow Sep 3, 2018 by Oliver Strong • edited Sep 3, 2018 by Oliver Strong

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0