+Robin Krens - robin@robinkrens.nl
ASFLAGS+= -mcpu=cortex-m3 -mthumb -g
CFLAGS+= -mcpu=cortex-m3 -mthumb -g -ffreestanding
+BIN = bin
+
ODIR = obj
-_OBJ = main.o uart.o ivt.o systick.o sysinfo.o lib.o regf.o pool.o
+_OBJ = ivt.o uart.o systick.o sysinfo.o lib.o regf.o pool.o term.o main.o
OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ))
-
-$(ODIR)/%.o: %.c $(DEPS)
+$(ODIR)/%.o: %.c
@mkdir -p $(@D)
$(CC) -c $< $(CFLAGS) -I./include -o $@
# Compile and link all
kernel: $(OBJ)
$(AS) $(ASFLAGS) -o start.o start.asm
- $(LD) -nostartfiles -Map $@.MAP -T link.ld -o $@.ELF start.o $^ --print-memory-usage
+ $(LD) -nostartfiles -Map $@.MAP -T link.ld -o $(BIN)/$@.ELF start.o $^ --print-memory-usage
@echo "Creating binary..."
- $(MKIMG) -Obinary -R .data $@.ELF $@.bin
+ @mkdir -p $(BIN)
+ $(MKIMG) -Obinary -R .data $(BIN)/$@.ELF $(BIN)/$@.bin
# Run in Qemu; note this is a patched version for stm32-f103c8
run:
- /usr/local/bin/qemu-system-arm -serial stdio -M stm32-f103c8 -kernel kernel.bin
+ /usr/local/bin/qemu-system-arm -serial stdio -M stm32-f103c8 -kernel $(BIN)/kernel.bin
# Examine all sections
examine-all:
- arm-none-eabi-objdump -D kernel.ELF | less
+ arm-none-eabi-objdump -D $(BIN)/kernel.ELF | less
# Examine just headers
examine-header:
- arm-none-eabi-objdump -x kernel.ELF | less
+ arm-none-eabi-objdump -x $(BIN)/kernel.ELF | less
# Flash kernel to board
flash:
- stm32flash -w kernel.bin -v /dev/ttyUSB0
+ stm32flash -w $(BIN)/kernel.bin -v /dev/ttyUSB0
.PHONY: clean
clean:
- rm -rf $(ODIR)/*.o start.o kernel.*
+ rm -rf $(ODIR)/*.o start.o $(BIN)/kernel.*
# Altijd handig deze template
#%.o: %.c
-/*
+/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
+ *
+ * $LOG$
+ * 2019/7/20 - ROBIN KRENS
+ * Initial version
+ *
+ * $DESCRIPTION$
* Example memory map for the Cortex-A3
* Implementations vary among manufacturers. This one is
* a STM32F013RC6. Addresses of peripherals vary amongst
* manufacturers of boards with similar chips
- *
+ *
+ * $USAGE$
+ * These are volatile memory addresses of 32 bit. The macro's
+ * MEM_VALUE and MEM_ADDR should used.
+ * In case you want to use a address on the lside of a assigment
+ * use volatile uint32_t * p = MEM_ADDR(0x20000000);
+ *
* */
-#define BSS_BASE ((volatile uint32_t *)(0x20000800)) //TODO: .data flexible siz
-#define TOTAL_MEM_SIZE 64000;
+#define OWRITE 0x01
+#define SETBIT 0x02
+#define CLRBIT 0x03
+
+/* Safety macro's to get the address or value */
+#define MEM_VALUE(addr) *((volatile uint32_t(*) (addr))
+#define MEM_ADDR(addr) ((volatile uint32_t *) (addr))
/* SYSTEM INFO AND DEBUG */
-#define MCU_ID ((volatile uint32_t*)( 0xE000ED00))
-#define FLASH_MEM ((volatile uint32_t*)( 0x1FFFF000))
+#define MCU_ID MEM_ADDR(0xE000ED00)
+#define FLASH_MEM MEM_ADDR(0x1FFFF000)
/* SYSTEM CONTROL BLOCK REGISTER */
-#define SCB_VTOR ((volatile uint32_t *)( 0xE000ED08)) // VECTOR TABLE
-#define SCB_VTOR_ST ((volatile uint32_t *)( 0xE000ED04)) // STATUS OF VECTOR
-#define SCB_CCR ((volatile uint32_t *)( 0xE000ED14)) // SET SOFTWARE TRAPS
+#define SCB_VTOR MEM_ADDR(0xE000ED08) // VECTOR TABLE
+#define SCB_VTOR_ST MEM_ADDR(0xE000ED04) // STATUS OF VECTOR
+#define SCB_CCR MEM_ADDR(0xE000ED14) // SET SOFTWARE TRAPS
/* NESTED VECTOR INTERRUPT CONTROL REGISTER */
-#define NVIC_ISER0 ((volatile uint32_t*)( 0xE000E100)) // interrupt set enable register
-#define NVIC_ISER1 ((volatile uint32_t*)( 0xE000E104)) // interrupt set enable register
+#define NVIC_ISER0 MEM_ADDR(0xE000E100) // interrupt set enable register
+#define NVIC_ISER1 MEM_ADDR(0xE000E104) // interrupt set enable register
/* SYSTICK REGISTER */
-#define STK_CTRL ((volatile uint32_t *)(0xE000E010))
-#define STK_RELOAD ((volatile uint32_t *)(0xE000E014))
+#define STK_CTRL MEM_ADDR(0xE000E010)
+#define STK_RELOAD MEM_ADDR(0xE000E014)
/* CLOCK REGISTER */
-#define RCC_CR ((volatile uint32_t *)(0x40021000))
-#define RCC_CFGR ((volatile uint32_t *)(RCC_CR + 0x04))
+#define RCC_CR MEM_ADDR(0x40021000)
+#define RCC_CFGR MEM_ADDR(0x40021004)
/* SYSTEM CONTROL REGISTER */
-#define SYSCTRL_RCC ((volatile unsigned long *)(0x40021000))
-#define RCC_APB2ENR ((volatile uint32_t *)(0x40021018)) // register to enable USART1
+#define SYSCTRL_RCC MEM_ADDR(0x40021000)
+#define RCC_APB2ENR MEM_ADDR(0x40021018) // register to enable USART1
-#define SYSCTRL_RIS ((volatile unsigned long *)(0x400FE050))
-#define SYSCTRL_RCGC1 ((volatile unsigned long *)(0x400FE104))
-#define SYSCTRL_RCGC2 ((volatile unsigned long *)(0x400FE108))
-#define GPIOPA_AFSEL ((volatile unsigned long *)(0x40004420))
+#define SYSCTRL_RIS MEM_ADDR(0x400FE050)
+#define SYSCTRL_RCGC1 MEM_ADDR(0x400FE104)
+#define SYSCTRL_RCGC2 MEM_ADDR(0x400FE108)
+#define GPIOPA_AFSEL MEM_ADDR(0x40004420)
-#define GPIOA_CRH ((volatile unsigned long *)(0x40010804))
+#define GPIOA_CRH MEM_ADDR(0x40010804)
-#define AFIO_EVCR ((volatile uint32_t *)(0x40010000))
-//#define AFIO_EXTICR1 ((volatile uint32_t *)(AFIO_EVCR + 0x08))
+#define AFIO_EVCR MEM_ADDR(0x40010000)
/* EXTERNAL INTERRUPTS */
-#define EXTI_IMR ((volatile uint32_t *)(0x40010400))
-#define EXTI_RTSR ((volatile uint32_t *) (EXTI_IMR + 0x08))
-//#define EXTI_FTSR ((volatile uint32_t *) (EXTI_IMR + 0x04))
+#define EXTI_IMR MEM_ADDR(0x40010400)
+#define EXTI_RTSR MEM_ADDR(0x40010408)
/* UART1 REGISTERS */
-#define USART1_BASE ((volatile uint32_t) (0x40013800))
-#define USART1_SR ((volatile uint32_t *) (USART1_BASE))
-#define USART1_DR ((volatile uint32_t *) (USART1_BASE + 0x04))
-#define USART1_BRR ((volatile uint32_t *) (USART1_BASE + 0x08))
-#define USART1_CR1 ((volatile uint32_t *) (USART1_BASE + 0x0C))
-#define USART1_CR2 ((volatile uint32_t *) (USART1_BASE + 0x10))
-#define USART1_CR3 ((volatile uint32_t *) (USART1_BASE + 0x14))
+#define USART1_BASE MEM_ADDR(0x40013800)
+#define USART1_SR MEM_ADDR(0x40013800)
+#define USART1_DR MEM_ADDR(0x40013804)
+#define USART1_BRR MEM_ADDR(0x40013808)
+#define USART1_CR1 MEM_ADDR(0x4001380C)
+#define USART1_CR2 MEM_ADDR(0x40013810)
+#define USART1_CR3 MEM_ADDR(0x40013814)
extern void uart_init();
extern void uart_putc(unsigned char);
extern void uart_puts(unsigned char *);
+extern char uart_getc();
/* IVT.C */
extern void ivt_init();
extern void regw_u8(volatile uint32_t *, uint8_t, short, short);
extern void regw_u32(volatile uint32_t *, uint32_t, short, short);
+/* TERM.C */
+extern char getchar();
+extern void cputchar(char);
+extern void cputs(unsigned char *);
+extern char * readline();
+extern void terminal();
+
#endif
* interrupt vector 16-92: irq0 - irq ..
* */
-uint32_t ivt[92];
+uint32_t __attribute__((aligned(0x100))) ivt[92];
/* each message corresponds to each and every exception.
* We get the correct message by accessing
* a register in the NVIC called the vector table offset register */
//*SCB_VTOR = (volatile uint32_t) &ivt;
- regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, 0x01);
+ regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, OWRITE);
}
}
}
- //uart_puts("ADDRESS: 0x");
for (int i = 7; i >= 0; i--) {
- uart_putc(hexbuf[i]);
+ cputchar(hexbuf[i]);
}
- //uart_puts(hexbuf);
- //uart_putc('\n');
}
+
+
. = 0x0;
.text : ALIGN(4)
{
- /* (.vector_table */
+ /* (.vector_table */
*(.text)
*(.rodata)
}
{
*(.data)
}
- .bss : ALIGN(256)
+ .bss : ALIGN(4)
{
*(.bss)
}
{
ivt_init();
-// clock_init();
uart_init();
- //uart_puts("LOADING SYSTEM 0.1 ...\n");
+
systick_init();
-// mm_init();
- sysinfo();
-
-
- pool_init(20, 5, 0x20000800);
-
- //addrtohex(p2);
- //addrtohex(*p2);
-
- /* extern stub();
- stub();
- __asm__ __volatile__ ("udiv r1, r3 ,%0" :: "r"(0)); */
- //regw_u32(p, 0x0CCCCCCCC, 4, 0x01);
-
- //regw_u8(p, 0xFF, 0, 0x02);
+ sysinfo();
-// asm("cpsie i"); // enable irq , cpsied f (disable faukts(
+ terminal();
- // loop
for(;;) {
}
* Initial version
*
* $DESCRIPTION$
- * Fixed-sized memory pool allocation. A so called
- * memory-pool (i.e. 4kB * 12 blocks) can be
- * initialized. Note: this allocator is for use on
- * processors without an MMU (memory management
- * unit). A MPU (memory protection unit), if
- * available can be used to protect certain zones.
+ * Fixed-sized memory pool allocation. A so called * memory-pool
+ * (i.e. 4kB * 12 blocks) can be initialized. Note: this allocator
+ * is for use on processors without an MMU (memory management
+ * unit). A MPU (memory protection unit), if available can be used
+ * to protect certain zones.
*
- * This work is based on an article of Ben Kenwright
+ * This work is based on an article of Ben Kenwright.
*
- * Preconditions: programmer should make sure the
- * SRAM entry point + (blocks * blocksize) is free.
+ * Preconditions: programmer should make sure the SRAM entry point
+ * + (blocks * blocksize) is free.
*
* $SAMPLE USAGE$
- * KERNEL: can use initialize a big pool for all
- * user tasks
+ * KERNEL: can initialize a big pool for all user tasks
*
- * USER TASKS/PROCESS: can use this to dynamically
- * allocate their own memory (i.e. heap)
+ * USER TASKS/PROCESS: can use this to dynamically allocate their
+ * own memory (i.e. heap)
*
*
* * */
mem.SRAM_entry = NULL;
} */
+/* Helper functions */
uint32_t * AddrFromIndex(unsigned int i) {
return mem.SRAM_entry + ( i * mem.block_size );
}
+/* alloc and free */
void * alloc() {
if (mem.blocks_alloc < mem.blocks ) {
unsigned int * p = (unsigned int *)AddrFromIndex( mem.blocks_alloc );
#include <stddef.h>
#include <stdint.h>
#include <stm32.h>
-
-#define O_WRITE 0x01
-#define SET 0x02
-#define CLEAR 0x03
+#include <mmap.h>
/* write value (uint8_t) to register */
void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) {
switch(flag) {
- case O_WRITE:
- (*(volatile uint32_t *) (reg)) = (val << shift);
+ case OWRITE:
+ *reg = (val << shift);
break;
- case SET:
- (*(volatile uint32_t *) (reg)) =
- ((*(volatile uint32_t *) (reg)) | (val << shift));
+ case SETBIT:
+ *reg = *reg | (val << shift);
break;
- case CLEAR:
- (*(volatile uint32_t *) (reg)) = (val << shift);
+ case CLRBIT:
+ *reg = (val << shift);
break;
}
}
void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) {
switch(flag) {
- case O_WRITE:
- (*(volatile uint32_t *) (reg)) = (val << shift);
+ case OWRITE:
+ //*reg = (val << shift);
+ *reg = (val << shift);
+ break;
+ case SETBIT:
+ *reg = *reg | (val << shift);
break;
- case SET:
- (*(volatile uint32_t *) (reg)) =
- ((*(volatile uint32_t *) (reg)) | (val << shift));
- case CLEAR:
+ case CLRBIT:
//
break;
}
void sysinfo() {
uint32_t tmp = *MCU_ID;
- uart_puts("# ROBSYS 0.1 LOADING...\n");
- uart_puts("# DEVICE ID: ");
+ cputs("# ROBSYS 0.1 LOADING...\n");
+ cputs("# DEVICE ID: ");
if (tmp & 0x414)
- uart_puts("HIGH DENSITY\n");
+ cputs("HIGH DENSITY\n");
else {
- uart_puts("UNKNOWN\n");
+ cputs("UNKNOWN\n");
}
tmp = (tmp >> 16);
uart_puts("# REVISION: ");
switch (tmp) {
case 0x1000:
- uart_puts("REVISION A\n");
+ cputs("REVISION A\n");
break;
case 0x1001:
- uart_puts("REVISION Z\n");
+ cputs("REVISION Z\n");
break;
case 0x1003:
- uart_puts("REVISION 1/2/3/X/Y\n");
+ cputs("REVISION 1/2/3/X/Y\n");
break;
default:
- uart_puts("UNKNOWN\n");
+ cputs("UNKNOWN\n");
}
extern char _endofbss;
uint32_t data_bss = &_endofbss - MEM_OFFSET;
uint32_t mem_free = MEM_SIZE - stack_usage - data_bss;
- uart_puts("# TOTAL MEMORY: ");
+ cputs("# TOTAL MEMORY: ");
addrtohex(MEM_SIZE);
- uart_putc('\n');
- uart_puts("# FREE MEMORY: ");
+ cputchar('\n');
+ cputs("# FREE MEMORY: ");
addrtohex(mem_free);
- uart_putc('\n');
- uart_puts("# STACK USAGE: ");
+ cputchar('\n');
+ cputs("# STACK USAGE: ");
addrtohex(stack_usage);
- uart_putc('\n');
+ cputchar('\n');
}
void * systick_handler(/* struct interrupt_frame * frame */) {
// uint32_t volatile status;
- uart_puts("TICKING\n");
+ //uart_puts("TICKING\n");
// for(;;);
}
--- /dev/null
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stm32.h>
+#include <mmap.h>
+
+#define SERIAL 1
+#define BUFSIZE 256
+
+static char buf[BUFSIZE];
+
+/* Abstraction layer for I/O communication */
+
+char getchar(void) {
+ char c;
+ if (SERIAL) {
+ while ((c = uart_getc()) == 0);
+ /* do nothing */
+ }
+ return c;
+}
+
+void cputchar(char c) {
+
+ if (SERIAL) {
+ uart_putc(c);
+ }
+
+}
+
+void cputs(unsigned char *str) {
+
+ int i;
+ for (i = 0; i < strlen(str); i++) {
+ cputchar(str[i]);
+ }
+
+}
+
+void terminal() {
+
+ char *buf;
+ cputs("Terminal running!\n");
+
+ while (1) {
+ buf = readline("> ");
+ /* if (buf != NULL)
+ if (runcmd(buf, tf) < 0)
+ break; */
+ }
+}
+
+char * readline(char *prompt)
+{
+ int i, c, echoing;
+
+ if (prompt != NULL)
+ cputs(prompt);
+
+ i = 0;
+ echoing = 1;
+ while (1) {
+ c = getchar();
+ if (c < 0) {
+ cputs("read error");
+ return NULL;
+ } else if ((c == '\b' || c == '\x7f') && i > 0) {
+ if (echoing)
+ cputchar('\b');
+ i--;
+ } else if (c >= ' ' && i < BUFSIZE-1) {
+ if (echoing)
+ cputchar(c);
+ buf[i++] = c;
+ } else if (c == '\n' || c == '\r') {
+ if (echoing)
+ cputchar('\n');
+ buf[i] = 0;
+ return buf;
+ }
+ }
+}
#include <stdint.h>
#include <stm32.h>
#include <mmap.h>
+#include <drivers.h>
#define RXNE ((*USART1_SR >> 5) & 0x1)
+#define UARTBUF 256
+#define ECHO 1
+
+static struct {
+ uint8_t buf[UARTBUF] ;
+ uint32_t rpos;
+ uint32_t wpos;
+} linefeed;
-#define O_WRITE 0x01
-#define SET 0x02
-#define CLEAR 0x03
void * uart_handler() {
- uart_puts("echo: ");
+ //uart_puts("echo: ");
while (RXNE) {
char echochar = *USART1_DR;
+ //uart_putc(echochar);
+ linefeed.buf[linefeed.wpos++] = echochar;
+ if (linefeed.wpos == UARTBUF)
+ linefeed.wpos = 0;
//regw_u32(USART1_DR, echochar, 0, O_WRITE);
- uart_putc(echochar);
}
- uart_putc('\n');
+ //uart_putc('\n');
-
}
-void uart_init() {
- // global interrupt setup
-// regw_u32(EXTI_IMR, 0x000FFFFF, 0, O_WRITE);
-// regw_u32(EXTI_RTSR, 0x000FFFFF, 0, O_WRITE);
+void uart_init() {
-
- regw_u32(RCC_APB2ENR, 0x4005, 0, SET);// enable clock to UART1, AFIO and GPIOA
+ regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA
/* (after enable GPIOA), on PA9&PA10 and set mode
* to alternative output */
- regw_u32(GPIOA_CRH, 0x444444D4, 0, O_WRITE);
- regw_u8(AFIO_EVCR, 0x89, 0, O_WRITE);// set event control register, output on PA, Pin 9
+ regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE);
+ regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9
//disable temporarily to set values
- regw_u8(USART1_CR1, 0x0, 13, SET);
+ regw_u8(USART1_CR1, 0x0, 13, SETBIT);
/* baud rate 115200, 8MHz / (16 * USARTDIV)
* USARTDIV = 4.34
* MANTISSA: 0d4.34 0d4 -> 0x4
* USART_BRR = 0x45*/
- regw_u32(USART1_BRR, 0x00000045, 0, O_WRITE);
- regw_u32(USART1_CR2, 0x0000, 0, O_WRITE); //set stop bit, default is 1 stop bit 0x00
+ regw_u32(USART1_BRR, 0x00000045, 0, OWRITE);
+ regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00
/* parity = 8 bit, UART1 enabled,
* TX and RX enabled, interrupts enabled */
//regw_u32(USART1_CR1, 0x000030AC, 0, O_WRITE);
- regw_u32(USART1_CR1, 0x0000302C, 0, O_WRITE);
+ regw_u32(USART1_CR1, 0x0000302C, 0, OWRITE);
ivt_set_gate(53, uart_handler, 0);
*NVIC_ISER1 = (1 << 5); // Enable UART interrupt at NVIC
}
-void wait() {
+static void wait() {
for (int i = 0; i < 100; i++);
}
if (ch == '\n') {
while (*USART1_SR & 0x0C) { } // transmit data register empty and complete
- regw_u8(USART1_DR, 0x0D, 0, O_WRITE); // return line
+ regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line
}
while (*USART1_SR & 0x0C) {}
- regw_u8(USART1_DR, ch, 0, O_WRITE);
+ regw_u8(USART1_DR, ch, 0, OWRITE);
wait();
}
+char uart_getc(void) {
+ char c;
+
+ if (linefeed.rpos != linefeed.wpos) {
+ c = linefeed.buf[linefeed.rpos++];
+ if (linefeed.rpos == UARTBUF)
+ linefeed.rpos = 0;
+ return c;
+ }
+ return 0;
+ }
+
+
+// move to library
extern void uart_puts(unsigned char *str) {
int i;
for (i = 0; i < strlen(str); i++) {
}
}
-
-
-char uart_read() {
-
- /* while (buffer not empty)
- * read()
- * uart_putc(ch) // echo
- * if ch = enter
- * process inquiry.
- */
-
-}
-
-