From: Robin Krens Date: Wed, 14 Aug 2019 18:17:55 +0000 (+0800) Subject: added commenting, removed deprecated functions X-Git-Url: https://robinkrens.nl/gitweb/?p=cortex-from-scratch;a=commitdiff_plain;h=43b1749173f70bdf67884d920b93f6a5b1f19a1d added commenting, removed deprecated functions --- diff --git a/Makefile b/Makefile index 678ac90..949e287 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,11 @@ AS=arm-none-eabi-as MKIMG=arm-none-eabi-objcopy # Compiler flags -# TODO:Cortex-m3 or Cortex-m0? LDFLAGS+= -mthumb -mcpu=cortex-m3 ASFLAGS+= -mcpu=cortex-m3 -mthumb -g CFLAGS+= -mcpu=cortex-m3 -mthumb -g -ffreestanding +# Include directory INCLUDE+= -Iinclude BIN = bin diff --git a/README.md b/README.md new file mode 100644 index 0000000..605b49a --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# CORTEX M3 FROM SCRATCH + +This is my little 'Cortex M3 from scratch' project. No external libraries +or IDEs are used. Everything is written from scratch. My development environment +consist of nothing more than: + + * GCC-arm-none (standard ARM cross compiler) + * VIM editor + * stm32flash + +The board I use is a cheap Chinese STM32F103 ripoff. In theory, you should be able to +port this code to any Cortex M0/M3/M4/M7 board. + +## PROGRESS STATUS +Setup bare development environment [COMPLETED] + FILES: Makefile, link.d +Boot and jump to C [COMPLETED] + FILES: start.asm, main.c, include/sys/mmap.h, include/sys/robsys.h +Interrupt Handling [COMPLETED] + FILE: ivt.c, lib/string.c +Basic input and output (UART) [COMPLETED] + FILES: driver/uart.c, lib/stdio.c +SysTick [COMPLETED] + FILE: systick.c +System Info [COMPLETED] + FILE: sysinfo.c +High Speed External Clock / tuning [COMPLETED] + FILE: clock.c +RTC (Real Time Clock) [COMPLETED] + FILE: rtc.c +Built-in-shell [COMPLETED] + FILE: term.c +Port printf/libc library [COMPLETED] + FILE: lib/tinyprintf.c +Basic drivers + EEPROM: driver/at24c.c [COMPLETED] + UART drivers/uart.c [COMPLETED] + LED segment display: drivers/tm1637.c [COMPLETED] + Temperature sensor: drivers/tsensor.c [IN PROGRESS] + OLED display [PLANNED] + Joystick [PLANNED] +Memory Management [IN PROGRESS] + FILE: lib/pool.c +User Mode [PLANNED] +System Call PendV implementation [PLANNED] +Stack trace debug [IN PROGRESS] +Memory Protection Unit [PLANNED] +Loadable programs from EEPROM [PLANNED] +Multiple processes and scheduling [PLANNED] + +## SCREENSHOTS +Here is a screenshot that shows the terminal just after booting: + +![Screenshot](https://github.com/robinkrens/cortex-from-scratch/raw/master/img/ +screenshot.png "screenshot") + + + + + diff --git a/clock.c b/clock.c index 02a26ab..498097c 100644 --- a/clock.c +++ b/clock.c @@ -5,7 +5,7 @@ * Initial version * * $DESCRIPTION$ - * 1. Routines to setup the high speed external (HSE) clock. + * Routines to setup the high speed external (HSE) clock. * Initially a (less accurate) high speed internal (HSI) * clock is used. PPL is enabled; HSE is input for PPL. * PPL is multiplied to get the desired clock speed. diff --git a/drivers/tm1637.c b/drivers/tm1637.c index 1d78f7a..86a18af 100644 --- a/drivers/tm1637.c +++ b/drivers/tm1637.c @@ -37,9 +37,6 @@ #define TIMEOUT 5000 -#define DOT true -#define NODOT false - #define WRITE_CMD 0x20 /* STM32F1 microcontrollers do not provide the ability to pull-up SDA and SCL lines. Their diff --git a/drivers/tsensor.c b/drivers/tsensor.c index 3799095..d1ebcd4 100644 --- a/drivers/tsensor.c +++ b/drivers/tsensor.c @@ -2,10 +2,11 @@ * * $LOG$ * 2019/8/4 - ROBIN KRENS - * Initial version + * PreInitial version * * $DESCRIPTION$ - * Temperature sensor + * Temperature sensor + * [in dev] * * */ @@ -29,7 +30,7 @@ bool s1, s2; void * update_handler() { - s1 = false; +/* s1 = false; s2 = false; ccr1 = 0xFFFFFFFF; ccr2 = 0xFFFFFFFF; @@ -74,7 +75,7 @@ bool s1, s2; printf("EDGE UP\n"); s1 = false; - s2 = false; + s2 = false; */ } static void reset() { diff --git a/drivers/uart.c b/drivers/uart.c index 0090ef2..5e53362 100644 --- a/drivers/uart.c +++ b/drivers/uart.c @@ -70,10 +70,10 @@ void uart_putc(unsigned char ch) { if (ch == '\n') { while(!rchkbit(USART1_SR, 6)); - regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line + rwrite(USART1_DR, 0x0D); // return line } while(!rchkbit(USART1_SR, 6)); - regw_u8(USART1_DR, ch, 0, OWRITE); + rwrite(USART1_DR, ch); } char uart_getc(void) { @@ -99,13 +99,10 @@ char uart_getc(void) { void set_baudrate() { -// rwrite(USART1_BRR, 0x000001A1); 48 MHZ -// rwrite(USART1_BRR, 0x0000022B); 64 MHz -// rwrite(USART1_BRR, 0x00000138); 36 MHz // rwrite(USART1_BRR, 0x00000271); 72 MHz #ifdef ENABLE_HSE - rwrite(USART1_BRR, 0x00000138); + rwrite(USART1_BRR, 0x00000138); // 36 MHz #else - rwrite(USART1_BRR, 0x00000045); + rwrite(USART1_BRR, 0x00000045); // 8 Mhz #endif } diff --git a/img/screenshot.png b/img/screenshot.png new file mode 100644 index 0000000..d2823f7 Binary files /dev/null and b/img/screenshot.png differ diff --git a/include/drivers/tm1637.h b/include/drivers/tm1637.h index 64e1f78..f9ada9c 100644 --- a/include/drivers/tm1637.h +++ b/include/drivers/tm1637.h @@ -1,6 +1,9 @@ #ifndef __TM1637_H #define __TM1637_H +#define DOT true +#define NODOT false + /* HELPER SUBROUTINES DECLARATIONS */ static void start_condition(); static void stop_condition(); diff --git a/include/lib/regfunc.h b/include/lib/regfunc.h index b13c28f..ca5992c 100644 --- a/include/lib/regfunc.h +++ b/include/lib/regfunc.h @@ -1,10 +1,13 @@ /* regfunc.h */ -extern char * regtohex(uint32_t ); -extern uint32_t hextoreg(char *); +/* DEPRECATED extern char * regtohex(uint32_t ); */ +extern uint32_t hextoreg(char *); // TODO: scanf extern void rsetbit(volatile uint32_t *, short); extern void rclrbit(volatile uint32_t *, short); extern void rsetbitsfrom(volatile uint32_t *, short, int); extern int rchkbit(volatile uint32_t *, short); extern void rwrite(volatile uint32_t *, uint32_t); -extern void regw_u8(volatile uint32_t *, uint8_t, short, short); -extern void regw_u32(volatile uint32_t *, uint32_t, short, short); + +/* DEPRECATED + * extern void regw_u8(volatile uint32_t *, uint8_t, short, short); + * extern void regw_u32(volatile uint32_t *, uint32_t, short, short); +*/ diff --git a/include/sys/robsys.h b/include/sys/robsys.h index 6962770..8070e60 100644 --- a/include/sys/robsys.h +++ b/include/sys/robsys.h @@ -9,8 +9,8 @@ * rates etc. */ //#define ENABLE_HSE -//efine CRYSTAL_MHZ 8 -//efine CLKSPEED_MHZ 72 +//#define CRYSTAL_MHZ 8 +//#define CLKSPEED_MHZ 72 extern void clock_init(); // extern int clock_test(); // extern void clock_reset(); diff --git a/ivt.c b/ivt.c index 02c45ec..d62a8dd 100644 --- a/ivt.c +++ b/ivt.c @@ -113,7 +113,6 @@ __attribute__ ((interrupt)) void * dummy_isr( struct interrupt_frame * frame ) { uint8_t nr = *SCB_VTOR_ST & 0xFF; - //printf("PC:%p\n",frame->lr); printf("EXCEPTION: %s\n", exception_message(nr)); printf("STACK TRACE:\n"); printf("R0:%p\n",frame->r0); @@ -149,6 +148,6 @@ void ivt_init() { * relocated to other memory locations. We can do this by setting * a register in the NVIC called the vector table offset register */ - regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, OWRITE); + rwrite(SCB_VTOR, (uint32_t) &ivt); } diff --git a/lib/regfunc.c b/lib/regfunc.c index 9ea7d7b..f5bc539 100644 --- a/lib/regfunc.c +++ b/lib/regfunc.c @@ -1,3 +1,14 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Helper functions to set registers + * + * */ + #include #include #include @@ -24,6 +35,7 @@ void rclrbit(volatile uint32_t * reg, short pos) { *reg = *reg & ~(0x1 << pos); } +// check if a bit is set int rchkbit(volatile uint32_t * reg, short pos) { if ((*reg >> pos) & 0x1) return 1; @@ -36,7 +48,7 @@ void rwrite(volatile uint32_t * reg, uint32_t val) { } -/* write value (uint8_t) to register */ +/* DEPRECATED write value (uint8_t) to register void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { switch(flag) { @@ -50,9 +62,9 @@ void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { *reg = *reg & ~(val << shift); break; } -} +} */ -/* write value (uint32_t) to register */ +/* DEPRECATED write value (uint32_t) to register void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) { switch(flag) { @@ -66,11 +78,9 @@ void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) { *reg = *reg & ~(val << shift); break; } -} - -/* Print out the hexidecimal representation of an integer - After implementation of scanf or sth this will be obsolete. */ +} */ +/* Deprecated use printf instead char hexbuf[8]; char * regtohex(uint32_t addr) { char tmpbuf[6] = {'A', 'B', 'C', 'D', 'E', 'F'}; @@ -89,7 +99,9 @@ char * regtohex(uint32_t addr) { } } return &hexbuf[0]; -} +} */ + +// TODO: implement simple scanf functions int singlehextoreg(char hex) { int conv = 0; diff --git a/lib/stdio.c b/lib/stdio.c index 9ef20ee..6b0f2a2 100644 --- a/lib/stdio.c +++ b/lib/stdio.c @@ -1,3 +1,17 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/23 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * The 'classic' putc and getchar functions. Should not be used directly + * use the tinyprintf library instead + * + * Can be extended for multiple interfaces (serial, tft or oled screens) + * + */ + #include #include #include diff --git a/lib/string.c b/lib/string.c index 2edc71a..933234c 100644 --- a/lib/string.c +++ b/lib/string.c @@ -1,10 +1,20 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Re-implementation of POSIX String functions + * + */ + #include #include #include #include -// TODO: add more void *memcpy(void *dest, void *src, size_t count) { const char *sp = (const char *)src; diff --git a/link.ld b/link.ld index 1f6b5f6..d8361dc 100644 --- a/link.ld +++ b/link.ld @@ -1,4 +1,26 @@ -/* */ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Linker file for Cortex-M3 STM32 based boards + * Boards have similar FLASH and SRAM ORIGINs + * LENGTHs differs of course. + * + * _start flag is the first procedure to be + * executed (linked to beginning of FLASH at + * 0x08000000). The procedure should do some + * basic things, such as set up the stack and + * reset and hard fault handler (see start.asm) + * * + * _endofbss flag is used to calculate the end + * of .bss and the start of (a possible) kernel + * heap + * + * */ + MEMORY { FLASH (xr) : ORIGIN = 0x08000000, LENGTH = 512K diff --git a/main.c b/main.c index da28711..221d7d6 100644 --- a/main.c +++ b/main.c @@ -5,7 +5,7 @@ * Initial version * * $DESCRIPTION$ - * Main intialize basic components of the boards + * Main initialize basic components of the board * and jumps to a terminal * * */ @@ -24,77 +24,50 @@ #include #include #include -#include +//#include #include -//void sleep() { -// -// __asm__ __volatile__("wfe"); -// -//} - void main() { + + /* Initialize the clock system, */ clock_init(); + + /* Setup the interrupt vector table */ ivt_init(); + + /* Initialze basic input and output over serial */ uart_init(); -// cputs("ROBSYS LOADING...\n"); - //systick_init(); -// tsensor_output(0xFFFF, 0x7FFF); + /* Cortex M* integrated systick, can be replaced + * by the more accurate RTC. + systick_init(); + */ + + /* Set up a very small libc library */ init_printf(NULL, putc); - // SPEED_TEST -/* cputs("START TEST (8MHz) \n"); - int a; - for (int i = 0; i < 20000000; i++) { - a + 2; - } - a = 0; - cputs("END TEST\n"); - - //! - clock_init(); - cputs("START TEST (??MHz) \n"); - for (int i = 0; i < 20000000; i++) { - a + 2; - } - cputs("END TEST\n"); */ + /* Display some basic info at startup */ sysinfo(); - -// tsensor_input(5000); -// run(); - + /* On board LEDs*/ led_init(); -// eeprom_at24c_init(); -// eeprom_test(); - tm1637_init(); + /* Real time clock */ rtc_init(); + /* Eeprom Driver + eeprom_at24c_init(); + eeprom_test(); + */ + + /* LED Segment Driver */ + tm1637_init(); - //uint32_t test = hextoreg("12345678"); - -// cputs(regtohex(test)); - - //extern void stub(); - //stub(); - //__asm__ __volatile__ ("ldc p1, cr1, r0"); - -/* while(1) { - int r; - for (int i = 0; i < 50000; i++) { - r = 0; - } - led_on(); - for (int i = 0; i < 50000; i++) { - r = 0; - } - led_off(); - } */ + /* Start up terminal */ terminal(); + /* Should not be here, endless loop */ for(;;) { } diff --git a/rtc.c b/rtc.c index 1f1136a..f169a85 100644 --- a/rtc.c +++ b/rtc.c @@ -46,18 +46,15 @@ void * rtc_handler() { grid2 = ((cntvalue % 1000) - grid0 - grid1) / 100; grid3 = ((cntvalue % 10000) - grid0 - grid1 - grid2) / 1000; - printf("%d, %d, %d, %d\n", grid0, grid1, grid2, grid3); - + //printf("%d, %d, %d, %d\n", grid0, grid1, grid2, grid3); char current[4] = { dn[grid3], dn[grid2], dn[grid1], dn[grid0] }; - //char current[4] = { dn[1], dn[1], dn[1], dn[1] }; for (int i = 0; i < 4; i++) { set_grid(i, current[i], false); } set_display(true, 0); - } // Simple LED blink diff --git a/start.asm b/start.asm index 180f9a4..f2c16bc 100644 --- a/start.asm +++ b/start.asm @@ -5,8 +5,10 @@ * Initial version * * $DESCRIPTION$ - * - * */ + */ + +/* _start sets up the stack and jumps to the reset vector */ + .equ STACK_TOP, 0x20010000 /* placed at 64kB, top of SRAM */ .text .global _start @@ -34,14 +36,6 @@ nmi: hardfault: b hardfault -.global stub -stub: - ldr R0,=10 - mov R1,#0 - ldc2 11, cr0, [r1, #4] - udiv.w R2, R0, R1 - - .data - .word 'x' + .end diff --git a/sysinfo.c b/sysinfo.c index bd5d1bb..2792f14 100644 --- a/sysinfo.c +++ b/sysinfo.c @@ -2,7 +2,9 @@ * * $LOG$ * 2019/7/20 - ROBIN KRENS - * Initial version + * Initial version + * Display some system information, calculate + * the amount of SRAM available * * */ @@ -50,18 +52,12 @@ void sysinfo() { uint32_t current_stack = get_msp(); uint32_t stack_usage = (SRAM_OFFSET + SRAM_SIZE) - current_stack; - uint32_t data_bss = &_endofbss - SRAM_OFFSET; + uint32_t data_bss = (uint32_t) &_endofbss - SRAM_OFFSET; uint32_t mem_free = SRAM_SIZE - stack_usage - data_bss; printf("# TOTAL MEMORY: %#x\n", SRAM_SIZE); -// cputs(regtohex(SRAM_SIZE)); -// cputchar('\n'); printf("# FREE MEMORY: %#x\n", mem_free); -// cputs(regtohex(mem_free)); -// cputchar('\n'); printf("# STACK USAGE: %#x\n", stack_usage); -// cputs(regtohex(stack_usage)); -// cputchar('\n'); } diff --git a/systick.c b/systick.c index 05f515f..589e286 100644 --- a/systick.c +++ b/systick.c @@ -1,3 +1,16 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/8/14 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * SysTick of Cortex M* MCUs. Have a look at the more complex RTC + * in case more accurate timing is needed. + * + * + * */ + #include #include #include @@ -6,7 +19,7 @@ #include #include -#include +#include struct interrupt_frame { @@ -23,15 +36,14 @@ struct interrupt_frame { //__attribute__ ((interrupt)) void * systick_handler(/* struct interrupt_frame * frame */) { -// cputs("TICKING\n"); -// for(;;); + printf("Ticking...\n"); } void systick_init() { /* Every time the counter counts down to zero - * a systick exception is asserted. Systick has + * a systick exception is invoked. Systick has * exception number 15. in the vector table */ ivt_set_gate(15, systick_handler, 0); diff --git a/term.c b/term.c index 7ce25ce..d1a6431 100644 --- a/term.c +++ b/term.c @@ -1,3 +1,14 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/8/14 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Small terminal with some built-in debug commands + * + * */ + #include #include #include @@ -18,15 +29,14 @@ #define WHITESPACE "\t\r\n " #define BUILTINCMDS 4 -int help(int, char**); - /* * Built in commands * info -- shows basic info of system * uptime -- uptime; read from the RTC register * reset -- software reset TODO - * show [ADDRESS-ADDRESS] -- shows SRAM range - * switchmode -- switch to unprivileged mode + * showmem xxxxxxxx -- shows address value + * led -- led on/off + * switchmode -- switch to unprivileged mode TODO * */ static char buf[BUFSIZE]; @@ -37,7 +47,7 @@ struct cmd { int (*function)(int argc, char ** argsv); }; -struct cmd builtincmds[4]; +struct cmd builtincmds[BUILTINCMDS]; int info(int argc, char ** argsv) { sysinfo(); @@ -45,38 +55,30 @@ int info(int argc, char ** argsv) { } int uptime(int arg, char ** argsv) { - //cputs("CURRENT UPTIME: "); - //cputs(regtohex(*RTC_CNTL)); - //cputchar('\n'); - printf("CURRENT UPTIME: %p\n", *RTC_CNTL); + printf("CURRENT UPTIME: %d seconds \n", *RTC_CNTL); } int led(int argc, char ** argsv) { - if (argsv[1] != NULL) { if (strcmp(argsv[1], "on")) { - cputs("LED ON\n"); + printf("LED ON\n"); led_on(); } else if (strcmp(argsv[1], "off")) { - cputs("LED OFF\n"); + printf("LED OFF\n"); led_off(); } } return 0; } -int show(int argc, char ** argsv) { +int showmem(int argc, char ** argsv) { if ((argsv[1] != NULL) && (strlen(argsv[1]) == 8)) { uint32_t * check = (uint32_t *) hextoreg(argsv[1]); - cputs("REGISTER 0x"); - cputs(argsv[1]); - cputs(" VALUE: "); - cputs(regtohex(*check)); - cputchar('\n'); + printf("LOCATION 0x%s, VALUE: %#x\n", argsv[1], *check); return 1; } @@ -102,7 +104,7 @@ int exec_cmd(char * buf) { // save and scan past next arg if (argc == MAXARGS-1) { - cputs("Too many arguments"); + printf("Too many arguments\n"); return 0; } argv[argc++] = buf; @@ -118,7 +120,7 @@ int exec_cmd(char * buf) { if (strcmp(argv[0], builtincmds[i].name)) return builtincmds[i].function(argc, argv); } - cputs("Unknown command"); + printf("Unknown command\n"); return 0; } @@ -131,15 +133,14 @@ void terminal() { builtincmds[1].name = "led"; builtincmds[1].function = led; - builtincmds[2].name = "show"; - builtincmds[2].function = show; + builtincmds[2].name = "showmem"; + builtincmds[2].function = showmem; builtincmds[3].name = "uptime"; builtincmds[3].function = uptime; char *buf; - //cputs("WELCOME TO ROBSYS!\n"); while (1) { buf = readline("root# ");