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.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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