diff options
Diffstat (limited to 'md')
| -rw-r--r-- | md/index.md | 5 | ||||
| -rw-r--r-- | md/writeup/raspberry5_baremetal_uart.md | 255 | 
2 files changed, 259 insertions, 1 deletions
diff --git a/md/index.md b/md/index.md index 5b9d384..4dd1538 100644 --- a/md/index.md +++ b/md/index.md @@ -5,7 +5,10 @@ title: Writeup page  ## Writeup's  <!-- Test [AM modulation](writeup/am_modulation.md)--> - +[WIP] [Raspberry PI5 baremetal GPIO](writeup/raspberry5_baremetal_gpio.md)   +[WIP] [GDB Python scripting](writeup/gdb_python_scripting.md)   +[Raspberry PI5 baremetal UART](writeup/raspberry5_baremetal_uart.md)   +[Raspberry PI5 baremetal detect board](writeup/raspberry5_baremetal_detect_board.md)    [Raspberry PI5 baremetal hello world](writeup/raspberry5_baremetal_helloworld.md)    [Kernel programming](notes/kernel/topics.md)    [QEMU ARM64](writeup/qemu_arm64.md)   diff --git a/md/writeup/raspberry5_baremetal_uart.md b/md/writeup/raspberry5_baremetal_uart.md new file mode 100644 index 0000000..f6500da --- /dev/null +++ b/md/writeup/raspberry5_baremetal_uart.md @@ -0,0 +1,255 @@ +title: Raspberry 5 baremetal UART example +keywords:raspi5,asm,c,kernel,arm64,uart,tty,serial + +# Raspberry 5 bare metal UART example + + +## Intro + +As base can check the [/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md)  + + +Getting basic communication for Raspberry 5 UART bare metal.  + +## Enabling UART + +To find out MMIO base for UART, first step to set flag so  +PCIe bus doesn't reset UART,  + +``` +enable_rp1_uart=1 +``` + +if flag is set then UART will output string  +``` +RP1_UART 0000001c00030000 +``` + +where MMIO base is  + +```c +#define MMIO_BASE  0x1c00000000UL +``` + +and UART base  +```c +#define PL011_REG_OFFSET MMIO_BASE+0x30000 +``` + +## Configure UART + +Disable UART before configure it and then set desired settings. +This case just to set to 8 bit mode. After configuration done +enable RX/TX and UART.  + +```c +	//disable UART +	pl011_write32(PL011_CR,0x0); +	//config uart +	pl011_write32(PL011_LCRH, PL011_LCRH_WLEN_8BIT); +	//enable UART +	pl011_write32( +		PL011_CR, +		PL011_CR_UARTEN|PL011_CR_TXE|PL011_CR_RXE +		); +``` + +## Sending first characters + +Sending characters is done by writing 8 bits to register DR + +```c +#define PL011_DR    0x00 /* Data read or written from the interface. */ +``` + +if just write then raspi5 will do it faster then UART can process and +characters will be lost in basic case only first 2 characters where out. +So before writing to DR check that TX FIFO is not full and wait if its full + +```c +void pl011_putc(const uint8_t c) { +	while (pl011_read32(PL011_FR)&PL011_FR_TXFF); +	pl011_write32(PL011_DR,c); +} +``` + +## Receiving characters + +to receive characters read register DR and to check if RX is empty +check registers FR RX FIFO Empty flag. + +```c +uint8_t pl011_getc() { +	return pl011_read8(PL011_DR);	 +} +``` + +## Basic command line  + +Here is basic echo terminal loop that echo's back characters sent over UART. +Loop checks FR register to see if RX FIFO isn't empty, and read character. +Extra processing set for Enter to output "\r\n" and move to new line + +```c +while (1) { +		uint32_t rx_status = pl011_read32(PL011_FR); +		//empty? if not printout +		if (!(rx_status&PL011_FR_RXFE)) { +			uint8_t c = pl011_read8(PL011_DR); +			if (c == 0xD) { +				pl011_puts("\r\n"); +			} else { +				pl011_write8(PL011_DR,c); +			} +		} +	} +``` + +## Source code +For base setup check hello world example [/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md)  + +### pl011.h +```c +#ifndef __PL011_H +#define __PL011_H + +//#include <stdint.h> + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +//static for now for raspi5 +#define MMIO_BASE  0x1c00000000UL +#define PL011_REG_OFFSET MMIO_BASE+0x30000 + + +#define PL011_DR    0x00 /* Data read or written from the interface. */ + +#define PL011_FR    0x18 /* Flag register (Read only). */ +#define PL011_IBRD  0x24 /* Integer baud rate divisor register. */ +#define PL011_FBRD  0x28 /* Fractional baud rate divisor register. */ +#define PL011_LCRH  0x2c /* Line control register. */ +#define PL011_CR    0x30 /* Control register. */  +#define PL011_IFLS  0x34 /* Interrupt fifo level select. */ +#define PL011_IMSC  0x38 /* Interrupt mask. */ +#define PL011_RIS   0x3c /* Raw interrupt status. */ +#define PL011_MIS   0x40 /* Masked interrupt status. */ +#define PL011_ICR   0x44 /* Interrupt clear register. */ +#define PL011_DMACR 0x48 /* DMA control register. */ + +#define PL011_FR_RXFE (1 << 4)/* RX FIFO Empty */ +#define PL011_FR_TXFF (1 << 5)/* TX FIFO full */ + +#define PL011_LCRH_WLEN_8BIT  (3 << 5)  /* 8bit */ + +#define PL011_CR_CTSEN        (1 << 15)	/* CTS hardware flow control enable */ +#define PL011_CR_RTSEN        (1 << 14)	/* RTS hardware flow control enable */ +#define PL011_CR_RTS          (1 << 11)	/* Request to send */ +#define PL011_CR_DTR          (1 << 10)	/* Data transmit ready. */ +#define PL011_CR_RXE          (1 << 9)	/* Receive enable */ +#define PL011_CR_TXE          (1 << 8)	/* Transmit enable */ +#define PL011_CR_LBE          (1 << 7)	/* Loopback enable */ +#define PL011_CR_UARTEN       (1 << 0)	/* UART Enable */ + +#define pl011_read8(offset) (*(volatile uint8_t *)(PL011_REG_OFFSET+offset)) +#define pl011_write8(offset,val) (*(volatile uint8_t *)(PL011_REG_OFFSET+offset)) = val +#define pl011_read32(offset) (*(volatile uint32_t *)(PL011_REG_OFFSET+offset)) +#define pl011_write32(offset,val) (*(volatile uint32_t *)(PL011_REG_OFFSET+offset)) = val + +void pl011_init(); +void pl011_putc(const uint8_t c); +void pl011_puts(const char *str); +uint8_t pl011_getc(); + +``` +### pl011.c +```c + +#include "pl011.h" + +void pl011_init() { +	//disable UART +	pl011_write32(PL011_CR,0x0); +	//config uart +	pl011_write32(PL011_LCRH, PL011_LCRH_WLEN_8BIT); +	//enable UART +	pl011_write32( +		PL011_CR, +		PL011_CR_UARTEN|PL011_CR_TXE|PL011_CR_RXE +		); +} + +void pl011_putc(const uint8_t c) { +	while (pl011_read32(PL011_FR)&PL011_FR_TXFF); +	pl011_write32(PL011_DR,c); +} + +void pl011_puts(const char *str) { +	uint16_t cnt = 0; +	while (cnt<256) { +		if (str[cnt] != 0) { +			pl011_putc(str[cnt]); +		} else { +			break; +		} +		cnt++; +	} +} +uint8_t pl011_getc() { +	return pl011_read8(PL011_DR); +	 +} +``` + +### kernel.c +```c +#include <pl011.h> + +void main() +{ +	pl011_init(); +	pl011_puts("Raspberry Pi5 UART demo?!\r\n"); +	while (1) { +		uint32_t rx_status = pl011_read32(PL011_FR); +		//empty? if not printout +		if (!(rx_status&PL011_FR_RXFE)) { +			uint8_t c = pl011_read8(PL011_DR); +			if (c == 0xD) { +				pl011_puts("\r\n"); +			} else { +				pl011_write8(PL011_DR,c); +			} +		} +	} + +} +``` + +Creating Makefile and linker script is left as exercise + +## Links +https://github.com/BarrelfishOS/barrelfish/blob/master/kernel/arch/arm/pl011.c   +https://github.com/DSERIOUSGUY/HobOS/blob/main/uart.c   +https://github.com/rsta2/circle/blob/master/lib/serial.cpp   +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/tty/serial/amba-pl011.c?h=v6.16-rc4   +https://developer.arm.com/documentation/ddi0183/latest/   +[/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md)   +https://wiki.osdev.org/Detecting_Raspberry_Pi_Board   +https://github.com/dwelch67/raspberrypi/tree/master/uart01   +https://github.com/bztsrc/raspi3-tutorial/blob/master/03_uart1/uart.c   +https://www.rpi4os.com/part3-helloworld/   +https://www.valvers.com/open-software/raspberry-pi/bare-metal-programming-in-c-part-5/#aux-peripheral   +https://github.com/valvers/arm-tutorial-rpi/tree/master/part-5   +https://jsandler18.github.io/tutorial/boot.html   +https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/rpi/rpi5/include/rpi_hw.h   +https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/arm/pl011/aarch64/pl011_console.S   +https://elixir.bootlin.com/linux/v6.15.5/source/include/linux/amba/serial.h#L39   +https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/drivers/arm/pl011.h   +[/writeup/raspberry5_baremetal_helloworld.md](/writeup/raspberry5_baremetal_helloworld.md)  +https://krinkinmu.github.io/2020/11/29/PL011.html   +https://forums.raspberrypi.com/viewtopic.php?t=34112   +https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf   +https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf   +https://github.com/raspberrypi/linux/blob/rpi-6.12.y/arch/arm64/boot/dts/broadcom/bcm2712.dtsi   +https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf  
\ No newline at end of file  | 
