From: Robin Krens Date: Thu, 25 Jul 2019 14:33:25 +0000 (+0800) Subject: basic led gpio driver X-Git-Url: https://robinkrens.nl/gitweb/?a=commitdiff_plain;h=d35408aabe7ea757d406bf8a7dba669ee8736bd5;p=cortex-from-scratch basic led gpio driver --- diff --git a/Makefile b/Makefile index 520f0f1..3da9701 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ _OBJ = ivt.o systick.o sysinfo.o term.o main.o OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ)) DDIR = obj/drivers -_DRIVERS = uart.o +_DRIVERS = uart.o tm1637.o led.o DRIVERS = $(patsubst %, $(DDIR)/%,$(_DRIVERS)) LDIR = obj/lib diff --git a/drivers/led.c b/drivers/led.c new file mode 100644 index 0000000..0cdda5a --- /dev/null +++ b/drivers/led.c @@ -0,0 +1,47 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/25 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Hardly a driver, but a driver nonetheless. Enables clock on + * a GPIOx range and sets the GPIOx pin in push-pull output mode. + * Basic on - off function (writing a 1 or zero 0) + * + * $USAGE$ + * In the code below we enable GPIOC and use PC0 as output. But + * basically any GPIO range or pin could be used. Note that the + * output register is only word accessible. + * + * */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include + + +void led_init() { + + regw_u8(RCC_APB2ENR, 0x1, 4, SETBIT); // enable GPIOC + regw_u32(GPIOC_CRL, 0x44444442, 0, OWRITE); // set PC0 pin to output mode + *GPIOC_ODR = 0xFFFF; // only writable in word mode + +} + +void led_on() { + *GPIOC_ODR = 0x0001; +} + +void led_off() { + *GPIOC_ODR = 0x0000; +} + diff --git a/drivers/tm1637.c b/drivers/tm1637.c new file mode 100644 index 0000000..a4e3842 --- /dev/null +++ b/drivers/tm1637.c @@ -0,0 +1,44 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/25 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Basic driver for the TM1637. The TM1637 is 7 segment + * ledclock peripheral. Communication is over I2C. + * + * */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include + + +void tm1637_init() { + + /* Program the peripheral input clock in I2C_CR2 Register in order to generate correct timings + Configure the clock control registers + Configure the rise time register + Program the I2C_CR1 register to enable the peripheral + Set the START bit in the I2C_CR1 register to generate a Start condition + + ENABLE GPIOB6 and B7*/ + + //regw_u8(RCC_APB1ENR, 0x1, 21, SETBIT); + //regw_u32(RCC_APB2ENR, 0x1, 3, SETBIT); + // //regw_u8(AFIO_EVCR, 0x89, 0, SETBIT);// set event control register, output on ? + + // regw_u32(GPIOB_CRL, 0xEE444444, 0, OWRITE); + + +} + diff --git a/drivers/uart.c b/drivers/uart.c index 6fc940b..a107548 100644 --- a/drivers/uart.c +++ b/drivers/uart.c @@ -47,7 +47,7 @@ void uart_init() { /* (after enable GPIOA), on PA9&PA10 and set mode * to alternative output */ regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE); - regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 + regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 TODO: check //disable temporarily to set values regw_u8(USART1_CR1, 0x0, 13, SETBIT); diff --git a/include/drivers/led.h b/include/drivers/led.h new file mode 100644 index 0000000..8e090d8 --- /dev/null +++ b/include/drivers/led.h @@ -0,0 +1,4 @@ +extern void led_init(); +extern void led_on(); +extern void led_off(); + diff --git a/include/drivers/tm1637.h b/include/drivers/tm1637.h new file mode 100644 index 0000000..319d5c5 --- /dev/null +++ b/include/drivers/tm1637.h @@ -0,0 +1,6 @@ +#ifndef __TM1637_H +#define __TM1637_H + +extern void tm1637_init(); + +#endif diff --git a/include/sys/mmap.h b/include/sys/mmap.h index a5921d2..c3c91a1 100644 --- a/include/sys/mmap.h +++ b/include/sys/mmap.h @@ -22,6 +22,10 @@ #define SETBIT 0x02 #define CLRBIT 0x03 +/* 64kB SRAM located at SRAM_OFFSET */ +#define SRAM_SIZE 0x00010000 +#define SRAM_OFFSET 0x20000000 + /* 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)) @@ -49,6 +53,7 @@ /* SYSTEM CONTROL REGISTER */ #define SYSCTRL_RCC MEM_ADDR(0x40021000) +#define RCC_APB1ENR MEM_ADDR(0x4002101C) // register to enable I2C #define RCC_APB2ENR MEM_ADDR(0x40021018) // register to enable USART1 #define SYSCTRL_RIS MEM_ADDR(0x400FE050) @@ -56,7 +61,10 @@ #define SYSCTRL_RCGC2 MEM_ADDR(0x400FE108) #define GPIOPA_AFSEL MEM_ADDR(0x40004420) -#define GPIOA_CRH MEM_ADDR(0x40010804) +#define GPIOA_CRH MEM_ADDR(0x40010804) // for USART1 +#define GPIOB_CRL MEM_ADDR(0x40010C00) // low register (!) for I2C1 +#define GPIOC_CRL MEM_ADDR(0x40011000) // for led +#define GPIOC_ODR MEM_ADDR(0x4001100C) // #define AFIO_EVCR MEM_ADDR(0x40010000) diff --git a/ivt.c b/ivt.c index a6761d0..9f8e643 100644 --- a/ivt.c +++ b/ivt.c @@ -56,50 +56,42 @@ struct interrupt_frame { /* * Vector table, each entry contains an interrupt - * service routine: - * + * service routine: * interrupt vector 1-15: processor exceptions * interrupt vector 16-92: irq0 - irq .. - * * Vector table needs to be aligned in memory. * */ - uint32_t __attribute__((aligned(0x100))) ivt[92]; -/* each message corresponds to each and every exception. - * We get the correct message by accessing - * exception_message[interrupt_number] - * exception_message[0] is not used (=MSP)*/ - +/* Each message corresponds to each and every exception. */ char * exception_message(uint8_t intnr) { - char * messages[] = { - "--", - "RESET", - "NMI", - "HARD FAULT", - "MEMMANAGE FAULT", - "BUS FAULT", - "USAGE FAULT", - "RESERVED", - "SVC", - "DEBUG MONITOR", - "RESERVED", - "RESERVED", - "RESERVED", - "RESERVED", - "PENDSV", - "SYSTICK", - "IRQ1", - "IRQ2", - "IRQ3", - "IRQ4", - // add more if needed - }; - - if (intnr < 20) // TODO: strlen - return messages[intnr]; +char * messages[] = { + "--", + "RESET", + "NMI", + "HARD FAULT", + "MEMMANAGE FAULT", + "BUS FAULT", + "USAGE FAULT", + "RESERVED", + "SVC", + "DEBUG MONITOR", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "PENDSV", + "SYSTICK", + "IRQ1", + "IRQ2", + "IRQ3", + "IRQ4", + // add more if needed +}; +if (intnr < 20) // TODO: strlen + return messages[intnr]; return NULL; } @@ -107,11 +99,11 @@ void ivt_set_gate(unsigned char num, void * isr(), short pri) { ivt[num] = (uint32_t) isr; *NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F)); - /* Priorities */ + /* TODO: Priorities */ } -/* Dummy interrupt: comment out the comment to use a naked f +/* Dummy interrupt: comment out the comment to use a naked * function */ // __attribute__ ((interrupt)) @@ -129,13 +121,16 @@ void * dummy_isr(/* struct interrupt_frame * frame */) { /* Initialize interrupt vector */ void ivt_init() { - /* clear entire IVT, in SRAM location for SRAM + .data (in .bss section) */ + /* clear entire IVT location in memory */ memset(&ivt, 0, (sizeof(uint32_t) * 92)); - // stack top is loaded from the first entry table on boot/reset - // don't need to relocate or init this here + /* The reset, NMI and hardfault handlers are originally + * defined in the assembly start up and can be + * reused or overwritten. + * */ extern void * reset, * nmi, * hardfault; + // set dummy handlers for (int i = 1; i <= 64 ; i++) { ivt_set_gate(i, dummy_isr, 0); } diff --git a/main.c b/main.c index 35b718e..c5ee202 100644 --- a/main.c +++ b/main.c @@ -5,6 +5,8 @@ * Initial version * * $DESCRIPTION$ + * Main intialize basic components of the boards + * and jumps to a terminal * * */ @@ -16,21 +18,36 @@ #include #include +#include +#include void main() { ivt_init(); + uart_init(); - systick_init(); + + led_init(); sysinfo(); - extern void stub(); + //extern void stub(); //stub(); //__asm__ __volatile__ ("ldc p1, cr1, r0"); - terminal(); + 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(); + } + // terminal(); for(;;) { diff --git a/start.asm b/start.asm index 54d2b91..180f9a4 100644 --- a/start.asm +++ b/start.asm @@ -1,4 +1,13 @@ - .equ STACK_TOP, 0x20010000 /* placed at 32kB, TODO: could place at top of SRAM? */ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * + * */ + .equ STACK_TOP, 0x20010000 /* placed at 64kB, top of SRAM */ .text .global _start .global reset, nmi, hardfault diff --git a/sysinfo.c b/sysinfo.c index e9b2429..ba639a6 100644 --- a/sysinfo.c +++ b/sysinfo.c @@ -1,3 +1,11 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * */ + #include #include #include @@ -8,8 +16,6 @@ #include #include -#define MEM_SIZE 0x00010000 -#define MEM_OFFSET 0x20000000 uint32_t get_msp(void); @@ -44,12 +50,12 @@ void sysinfo() { extern char _endofbss; uint32_t current_stack = get_msp(); - uint32_t stack_usage = (MEM_OFFSET + MEM_SIZE) - current_stack; - uint32_t data_bss = &_endofbss - MEM_OFFSET; - uint32_t mem_free = MEM_SIZE - stack_usage - data_bss; + uint32_t stack_usage = (SRAM_OFFSET + SRAM_SIZE) - current_stack; + uint32_t data_bss = &_endofbss - SRAM_OFFSET; + uint32_t mem_free = SRAM_SIZE - stack_usage - data_bss; cputs("# TOTAL MEMORY: "); - cputs(regtohex(MEM_SIZE)); + cputs(regtohex(SRAM_SIZE)); cputchar('\n'); cputs("# FREE MEMORY: "); cputs(regtohex(mem_free));