Try   HackMD

Lab 4: UART0, PL011

This Lab does the same as Lab 3, but it prints the serial number on UART0. As such, it can be used easily with qemu.

GPIO.h

#define MMIO_BASE 0x3F000000 #define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) #define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) #define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) #define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) #define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) #define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) #define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) #define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) #define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) #define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) #define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) #define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) #define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) #define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) #define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) #define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) #define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) #define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C))

Uart.c

#include "gpio.h" /* Auxilary mini UART registers */ #define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) #define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) #define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) #define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) #define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) #define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) #define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) #define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) #define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) #define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) #define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) #define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) /** * Set baud rate and characteristics (115200 8N1) and map to GPIO */ void uart_init() { register unsigned int r; /* initialize UART */ *AUX_ENABLE |=1; // enable UART1, AUX mini uart *AUX_MU_CNTL = 0; *AUX_MU_LCR = 3; // 8 bits *AUX_MU_MCR = 0; *AUX_MU_IER = 0; *AUX_MU_IIR = 0xc6; // disable interrupts *AUX_MU_BAUD = 270; // 115200 baud /* map UART1 to GPIO pins */ r=*GPFSEL1; r&=~((7<<12)|(7<<15)); // gpio14, gpio15 r|=(2<<12)|(2<<15); // alt5 *GPFSEL1 = r; *GPPUD = 0; // enable pins 14 and 15 r=150; while(r--) { asm volatile("nop"); } *GPPUDCLK0 = (1<<14)|(1<<15); r=150; while(r--) { asm volatile("nop"); } *GPPUDCLK0 = 0; // flush GPIO setup *AUX_MU_CNTL = 3; // enable Tx, Rx } /** * Send a character */ void uart_send(unsigned int c) { /* wait until we can send */ do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); /* write the character to the buffer */ *AUX_MU_IO=c; } /** * Receive a character */ char uart_getc() { char r; /* wait until something is in the buffer */ do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); /* read it and return */ r=(char)(*AUX_MU_IO); /* convert carrige return to newline */ return r=='\r'?'\n':r; } /** * Display a string */ void uart_puts(char *s) { while(*s) { /* convert newline to carrige return + newline */ if(*s=='\n') uart_send('\r'); uart_send(*s++); } } /** * Display a binary value in hexadecimal */ void uart_hex(unsigned int d) { unsigned int n; int c; for(c=28;c>=0;c-=4) { // get highest tetrad n=(d>>c)&0xF; // 0-9 => '0'-'9', 10-15 => 'A'-'F' n+=n>9?0x37:0x30; uart_send(n); } }

Uart.h

void uart_init(); void uart_send(unsigned int c); char uart_getc(); void uart_puts(char *s); void uart_hex(unsigned int d);

Mbox.c

#include "gpio.h" /* mailbox message buffer */ volatile unsigned int __attribute__((aligned(16))) mbox[36]; #define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) #define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) #define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) #define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) #define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) #define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) #define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) #define MBOX_RESPONSE 0x80000000 #define MBOX_FULL 0x80000000 #define MBOX_EMPTY 0x40000000 /** * Make a mailbox call. Returns 0 on failure, non-zero on success */ int mbox_call(unsigned char ch) { unsigned int r = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); /* wait until we can write to the mailbox */ do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); /* write the address of our message to the mailbox with channel identifier */ *MBOX_WRITE = r; /* now wait for the response */ while(1) { /* is there a response? */ do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); /* is it a response to our message? */ if(r == *MBOX_READ) /* is it a valid successful response? */ return mbox[1]==MBOX_RESPONSE; } return 0; }

Mbox.h

/* a properly aligned buffer */ extern volatile unsigned int mbox[36]; #define MBOX_REQUEST 0 /* channels */ #define MBOX_CH_POWER 0 #define MBOX_CH_FB 1 #define MBOX_CH_VUART 2 #define MBOX_CH_VCHIQ 3 #define MBOX_CH_LEDS 4 #define MBOX_CH_BTNS 5 #define MBOX_CH_TOUCH 6 #define MBOX_CH_COUNT 7 #define MBOX_CH_PROP 8 /* tags */ #define MBOX_TAG_GETSERIAL 0x10004 #define MBOX_TAG_LAST 0 int mbox_call(unsigned char ch);

Main.c

#include "uart.h" #include "mbox.h" void main() { // set up serial console uart_init(); // get the board's unique serial number with a mailbox call mbox[0] = 8*4; // length of the message mbox[1] = MBOX_REQUEST; // this is a request message mbox[2] = MBOX_TAG_GETSERIAL; // get serial number command mbox[3] = 8; // buffer size mbox[4] = 8; mbox[5] = 0; // clear output buffer mbox[6] = 0; mbox[7] = MBOX_TAG_LAST; // send the message to the GPU and receive answer if (mbox_call(MBOX_CH_PROP)) { uart_puts("My serial number is: "); uart_hex(mbox[6]); uart_hex(mbox[5]); uart_puts("\n"); } else { uart_puts("Unable to query serial!\n"); } // echo everything back while(1) { uart_send(uart_getc()); } }

How to run


Previous Lab : Mailboxes

Next Lab : Random


Project Source Code: Bare-Metal-Mini-PiOS
Author : andykuo8766