From: Robin Krens Date: Tue, 13 Aug 2019 16:49:37 +0000 (+0800) Subject: Merge branch 'tm1637' X-Git-Url: https://robinkrens.nl/gitweb/?p=cortex-from-scratch;a=commitdiff_plain;h=8b8d6edcd57f69b40f430bc172e1c290a629a6a9;hp=09ef787389713bb6dbba15b603d0071af8709cb2 Merge branch 'tm1637' --- diff --git a/Makefile b/Makefile index 3da9701..678ac90 100644 --- a/Makefile +++ b/Makefile @@ -20,15 +20,15 @@ INCLUDE+= -Iinclude BIN = bin ODIR = obj -_OBJ = ivt.o systick.o sysinfo.o term.o main.o +_OBJ = ivt.o systick.o sysinfo.o term.o main.o clock.o rtc.o OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ)) DDIR = obj/drivers -_DRIVERS = uart.o tm1637.o led.o +_DRIVERS = uart.o tm1637.o led.o tsensor.o at24c.o DRIVERS = $(patsubst %, $(DDIR)/%,$(_DRIVERS)) LDIR = obj/lib -_LIBS = string.o stdio.o regfunc.o pool.o +_LIBS = string.o stdio.o regfunc.o pool.o tinyprintf.o LIBS = $(patsubst %, $(LDIR)/%,$(_LIBS)) $(DDIR)/%.o: drivers/%.c diff --git a/clock.c b/clock.c index 7d5dc19..02a26ab 100644 --- a/clock.c +++ b/clock.c @@ -1,15 +1,55 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/30 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * 1. 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. + * + * Some buses might not support the maximum speed and + * should be prescaled (i.e. low speed APB) + * + * $USAGE + * Check external crystals on board and maximum speed + * for buses. In this example, a 8 Mhz external crystal + * is used. CPU speed is 36 Mhz. No prescaling is done. + * + * */ + #include #include #include -#include -#include +#include +#include + +#include + +static void setup_hse() { + + rsetbit(RCC_CR, 16); /* HSE enable */ + rsetbit(RCC_CFGR, 17); /* HSE divider for PLL entry */ + + while(!rchkbit(RCC_CR, 17)); /* Wait for HSE to come up */ + + rsetbitsfrom(RCC_CFGR, 18, 0x7); /* PLL Multiplayer (x9) */ + rsetbit(RCC_CFGR, 16); /* HSE as PPL clock source */ + rsetbit(RCC_CR, 24); /* PLL enable */ + //rsetbitsfrom(RCC_CFGR, 8, 0x4); /* APB low speed prescraler */ + rsetbitsfrom(RCC_CFGR, 0, 0x2); /* use PPL as system clock */ + + while(!rchkbit(RCC_CFGR, 3)); /* Wait for the clock switch to complete */ +} void clock_init() { +#ifdef ENABLE_HSE +setup_hse(); +#endif - *RCC_CR = *RCC_CR | 0x00010000; - for (int i = 0; i < 200; i++) { - } - *RCC_CFGR = *RCC_CFGR | 0x05000001; } + diff --git a/drivers/at24c.c b/drivers/at24c.c new file mode 100644 index 0000000..7bf900a --- /dev/null +++ b/drivers/at24c.c @@ -0,0 +1,355 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/8/11 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Driver for AT24C256 EEPROM for STM32 based boards. Communication protocol is I2C + * Maximum write in limited to 64 bytes. Reading bytes is unlimited, but memory should + * be allocated accordingly. + * + * I2C protocol : (W)rite or (R)ead + * MCU is in master mode: either as transmitter or receiver + * | P | DEVICEADDR + R/W bit | ACK | ADDR_PART1 | ACK | ADDR_PART2 | (d+a*n) | (N)ACK | S + * Sending data: wait for ACK from EEPROM + * Receiving data: send (n)ACK to EEPROM after receiving data + * + * STM32F1 microcontrollers do not provide the ability to pull-up SDA and SCL lines. Their + * GPIOs must be configured as open-drain. So, you have to add two additional resistors to + * pull-up I2C lines. Something between 4K and 10K is a proven value. + * + * */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#define TIMEOUT 5000 +#define READ_CMD 0xA1 +#define WRITE_CMD 0xA0 +#define PAGE 64 /* Bytes that can be written continiously */ +#define BUFFER 64 /* Reading buffer */ + + +static char eeprombuf[BUFFER]; + +void eeprom_at24c_init() { + + /* Program the peripheral input clock generate correct timings. + * Configure the clock control registers CCR + * Configure the rise time register TRIS + * Program the I2C_CR1 register to enable the peripheral + * Enable GPIOB6 and B7*/ + + rsetbit(RCC_APB1ENR, 21); // enable GPIOB + rsetbit(RCC_APB2ENR, 3); // enable I2C + rwrite(GPIOB_CRL, 0xEE444444); // open-drain + rsetbitsfrom(I2C_CR2, 0, 0x2); // 2 MHz + rwrite(I2C_TRISE, 0x3); // MAX = 1000ns, TPCLK1 = 500ns (+1) + rwrite(I2C_CCR, 0x000A); // standard mode + rsetbit(I2C_CR2, 10); // buffer interrupt + rsetbit(I2C_CR1, 0); // enable + + +} + +/* Writes data to the EEPROM starting at address addr. Size can not + * be more than one PAGE (64 bytes) */ +int eeprom_write(uint16_t addr, char * data, size_t size) { + + if(size > PAGE) { + printf("Error: Maximum writable page size: %d\n", PAGE); + return -1; + } + + uint8_t hi_lo[] = { (uint8_t)(addr >> 8), (uint8_t)addr }; + + start_condition(); + rwrite(I2C_DR, WRITE_CMD); + if(!ack_recv()) + return -1; + + + rwrite(I2C_DR, hi_lo[0]); // higher part of address + if(!buf_empty()) + return -1; + + rwrite(I2C_DR,hi_lo[1]); // lower part of address + if(!buf_empty()) + return -1; + + + for (int i = 0; i < size; i++) { + rwrite(I2C_DR, *data++); + if(!buf_empty()) + return -1; + + } + + stop_condition(); + delay(); // wait for write action to finish + return 0; +} + +/* Erase (write all 0xFF) data on EEPROM + * Maximum hardware allowed sequential writes of 64 bytes */ +int eeprom_erase() { + + uint16_t cur_addr = 0x0000; + + for (int i = 0; i < 512; i++) { + + printf("Writing at address: %#x (64 bytes) ", cur_addr); + uint8_t hi_lo[] = { (uint8_t)(cur_addr >> 8), (uint8_t)cur_addr }; + + start_condition(); + rwrite(I2C_DR, WRITE_CMD); + if(!ack_recv()) + return -1; + + + rwrite(I2C_DR, hi_lo[0]); // higher part of address + if(!buf_empty()) + return -1; + + rwrite(I2C_DR,hi_lo[1]); // lower part of address + if(!buf_empty()) + return -1; + + + for (int i = 0; i < PAGE; i++) { + rwrite(I2C_DR, 0xFF); // write all ones + if(!buf_empty()) + return -1; + + } + stop_condition(); + printf("[COMPLETE]\n"); + cur_addr += 0x40; // 64 bytes; next PAGE + delay(); // wait for write to finish + } + + return 0; +} + +/* Random access read of num bytes + * Initialize dummy write first to set correct address location + * The read function differentiate between num = 1 num = 2 and num > 3 + * Data is saved to rvalues */ +int eeprom_read(uint16_t addr, int num, char * rvalues) { + + uint8_t hi_lo[] = { (uint8_t)(addr >> 8), (uint8_t)addr }; + + /* Dummy write to set address */ + start_condition(); + rwrite(I2C_DR, WRITE_CMD); + if(!ack_recv()) + return -1; + + rwrite(I2C_DR, hi_lo[0]); // higher part of address + if(!buf_empty()) + return -1; + + rwrite(I2C_DR,hi_lo[1]); // lower part of address + if(!buf_empty()) + return -1; + + stop_condition(); + + delay(); // wait form EEPROM + + switch(num) { + case 1: + start_condition(); // restart condition + rwrite(I2C_DR, READ_CMD); // read? to address CMD + if(!ack_recv()) + return -1; + stop_condition(); + + if(!data_recv()) + return -1; + + rvalues[0] = (char) *I2C_DR; + rvalues[1] = '\0'; + break; + case 2: + + rsetbit(I2C_CR1, 10); // set ACK + rsetbit(I2C_CR1, 11); // set POS + start_condition(); // restart condition + rwrite(I2C_DR, READ_CMD); // read to address CMD + if(!ack_recv()) + return -1; + rclrbit(I2C_CR1, 10); // clear ACK + if(!late_recv()) + return -1; + + stop_condition(); + + rvalues[0] = (char) *I2C_DR; + rvalues[1] = (char) *I2C_DR; + rvalues[2] = '\0'; + break; + + default: + rsetbit(I2C_CR1, 10); // set ACK + start_condition(); // restart condition + rwrite(I2C_DR, READ_CMD); // read to address CMD + if(!ack_recv()) + return -1; + + for(int i = 0; i < num-3; i++) { + if(!data_recv()) + return -1; + rvalues[i] = (char) *I2C_DR; + } + + if(!late_recv()) + return -1; + + rclrbit(I2C_CR1, 10); + rvalues[num-3] = *I2C_DR; + stop_condition(); + rvalues[num-2] = *I2C_DR; + if(!data_recv()) + return -1; + + rvalues[num-1] = *I2C_DR; + rvalues[num] = '\0'; + } + + return 0; + +} + +/* Dump all data on EEPROM to std out */ +int eeprom_dump() { + + uint16_t curr_addr = 0x0000; + + for (int i = 0; i < 512; i++) { + + if(eeprom_read(curr_addr, 64, eeprombuf) == -1) { + printf("Error: Can't (continue) dump"); + return -1; + } + printf("%#x:\n", curr_addr); + for (int i = 0; i < strlen(eeprombuf); i++) { + printf("%x ", eeprombuf[i]); + if (((i % 16) == 0) && (i != 0)) + printf("\n"); + } + printf("\n"); + curr_addr += 0x40; // 64 bytes + } + return 0; + +} + +/* HELPER SUBROUTINES */ + +static void start_condition() { + rsetbit(I2C_CR1, 8); //start bit +} + +static void stop_condition() { + rsetbit(I2C_CR1, 9); //stop bit +} + +/* Initial ACK received after address lookup + * read registers clear ADDR bit */ +static int ack_recv() { + int cnt = 0; + while(!(*I2C_SR1 & 0x2)) { + cnt++; + if (cnt > TIMEOUT) { + printf("Error: Can't reach device\n"); + return 0; + } + } + int a = *I2C_SR2; + return 1; +} + +/* Check send buffer + * Note: BLOCKING function */ +static int buf_empty() { + int cnt = 0; + while(!(*I2C_SR1 & 0x80)) { + cnt++; + if (cnt > TIMEOUT) { + printf("Error: Can't send data\n"); + return 0; + } + } + return 1; +} + +/* Check data receive buffer + * Note: BLOCKING function */ +static int data_recv() { + int cnt = 0; + while(!(*I2C_SR1 & 0x40)) { + cnt++; + if (cnt > TIMEOUT) { + printf("Error: Timeout receiving data\n"); + return 0; + } + } + return 1; +} + +/* Similar as above, waits for two packages to be received + * one in DR and one in the shadow register */ +static int late_recv() { + int cnt = 0; + while(!(*I2C_SR1 & 0x4)) { + cnt++; + if (cnt > TIMEOUT) { + printf("Error: Timeout receiving data\n"); + return 0; + } + } + return 1; + +} + +/* Write delay form EEPROM chip */ +static int delay() { + int a = 0; + for (int i = 0; i < 0xFFFF; i++) + a++; +} + + +int eeprom_test() { + char * gd = "Testing the EEPROM chip AT24C256 write and read function"; + eeprom_write(0x1000, gd, strlen(gd)); + + uint16_t curr_addr = 0x1000; + + for (int i = 0; i < 4; i++) { + + if(eeprom_read(curr_addr, 16, eeprombuf) == -1) { + printf("Can't (continue) dump"); + return -1; + } + printf("%#x: ", curr_addr); + for (int i = 0; i < strlen(eeprombuf); i++) { + printf("%x ", eeprombuf[i]); + } + printf("\n"); + curr_addr += 0x10; // 16 bytes + } +} + diff --git a/drivers/led.c b/drivers/led.c index 0cdda5a..ca74c14 100644 --- a/drivers/led.c +++ b/drivers/led.c @@ -31,17 +31,25 @@ 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 + rsetbit(RCC_APB2ENR, 5); // enable GPIOD + rsetbit(RCC_APB2ENR, 2); // enable GPIOA + + //rwrite(GPIOD_CRL, 0x44444644); + rsetbitsfrom(GPIOD_CRL, 8, 0x6); + rsetbitsfrom(GPIOA_CRH, 0, 0x6); +// rsetbit(GPIOD_ODR, 2); +// rclrbit(GPIOA_ODR, 8); } void led_on() { - *GPIOC_ODR = 0x0001; + rsetbit(GPIOD_ODR, 2); + rclrbit(GPIOA_ODR, 8); + } void led_off() { - *GPIOC_ODR = 0x0000; + rclrbit(GPIOD_ODR, 2); + rsetbit(GPIOA_ODR, 8); } diff --git a/drivers/tm1637.c b/drivers/tm1637.c index 485d81d..8c8ce5b 100644 --- a/drivers/tm1637.c +++ b/drivers/tm1637.c @@ -28,7 +28,7 @@ #include -#define TIMEOUT 1000 +#define TIMEOUT 5000 #define DOT true #define NODOT false @@ -221,7 +221,6 @@ void set_segment(int offset, char value, bool dot) { cputs("Error: can't set location\n"); stop_condition(); - regw_u32(I2C_CR1, 0x1, 15, SETBIT); tm1637_reset(); diff --git a/drivers/tsensor.c b/drivers/tsensor.c new file mode 100644 index 0000000..3799095 --- /dev/null +++ b/drivers/tsensor.c @@ -0,0 +1,226 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/8/4 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Temperature sensor + * + * */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#define PRESCALER 36000 // 1 Mhz + +int *ccr1, *ccr2, *ccr1b, *ccr2b; +bool s1, s2; + + void * update_handler() { + + s1 = false; + s2 = false; + ccr1 = 0xFFFFFFFF; + ccr2 = 0xFFFFFFFF; + ccr1b = 0xFFFFFFFF; + ccr2b = 0xFFFFFFFF; + + if(rchkbit(TIM4_SR1, 1)) { + s1 = true; + // printf("CCR1: %p\n", *TIM4_CCR1); + // printf("CCR2: %p\n", *TIM4_CCR2); + ccr1 = *TIM4_CCR1; + ccr2 = *TIM4_CCR2; + rclrbit(TIM4_SR1, 1); + } + + if(rchkbit(TIM4_SR1, 2)) { + s2 = true; + ccr1b = *TIM4_CCR1; + ccr2b = *TIM4_CCR2; + rclrbit(TIM4_SR1, 2); + } + + if(rchkbit(TIM4_SR1, 6)) { + // printf("TRIGGER\n"); + rclrbit(TIM4_SR1, 6); + } + + rclrbit(TIM4_SR1, 0); +// rclrbit(TIM4_SR1, 9); // OF +// rclrbit(TIM4_SR1, 10); // OF + + // TODO clear overflow tag + + printf("SR1/CCR1: %p\n", ccr1); + printf("SR1/CCR2: %p\n", ccr2); + printf("SR2/CCR1: %p\n", ccr1b); + printf("SR2/CCR2: %p\n", ccr2b); + + if (s1) + printf("EDGE DOWN\n"); + if (s2) + printf("EDGE UP\n"); + + s1 = false; + s2 = false; +} + +static void reset() { + rwrite(GPIOB_CRL, 0x44444444); +} + +void * tmp_update_handler() { + + printf("SR: %p\n", *TIM4_SR1); + + rclrbit(TIM4_CR1, 0); /* EMULATOR STOP */ + rclrbit(TIM4_SR1, 0); + rclrbit(TIM4_SR1, 1); + reset(); + tsensor_input(0xFFFF); + +// if(rchkbit(TIM4_SR1, 1)) { +// printf("TEST\n"); +// } + +} + +void * cnt_complete_handler() { + rclrbit(TIM4_CR1, 0); + rclrbit(TIM4_SR1, 0); + rclrbit(TIM4_DIER, 0); + rwrite(GPIOB_CRL, 0x44444444); + printf("CNT COMPLETE\n"); + tsensor_input(0xFFFF); +} + + +void tsensor_simple(uint16_t preload) { + + rsetbit(RCC_APB1ENR, 2); // TIM4 enable + + rsetbitsfrom(TIM4_CR1, 5, 0x00); // edge-aligned mode + rclrbit(TIM4_CR1, 4); // upcounter (clrbit! not needed to set) + rsetbit(TIM4_CR1, 2); // only overflow generates update + + rwrite(TIM4_PSC, PRESCALER - 1); + rwrite(TIM4_ARR, preload); + rsetbit(TIM4_EGR, 0); + + ivt_set_gate(46, cnt_complete_handler, 0); + rsetbit(NVIC_ISER0, 30); // interupt 41 - 32 + + rsetbit(GPIOB_BSRR, 22); // + rsetbit(TIM4_DIER, 0); + rsetbit(TIM4_CR1, 0); + +} + +void run() { + + rsetbit(RCC_APB2ENR, 3); // GPIOB enable + rwrite(GPIOB_CRL, 0x47444444); // open drain general + + rsetbit(GPIOB_BSRR, 22); // high + tsensor_simple(2000); +// tsensor_output(580, 520); +// reset(); +// tsensor_simple(580); +} + +void tsensor_output(uint16_t preload, uint16_t compare/*, uint16_t pulses */) { + + /* GPIO AND CLOCK */ + rsetbit(RCC_APB2ENR, 3); // GPIOB enable + rwrite(GPIOB_CRL, 0x4A444444); // PB6 for Channel 1 TIM4 alternate + rsetbit(RCC_APB1ENR, 2); // TIM4 enable + + rsetbitsfrom(TIM4_CR1, 5, 0x00); // edge-aligned mode + rclrbit(TIM4_CR1, 4); // upcounter (clrbit! not needed to set) + rsetbit(TIM4_CR1, 2); // only overflow generates update + + rwrite(TIM4_PSC, PRESCALER - 1); // 1 MHz + rwrite(TIM4_ARR, preload); // preload + rwrite(TIM4_CCR1, compare); // compare + //rwrite(TIM4_RCR, pulses - 1); /* repeat ONLY IN ADVANCED TIMER */ + + rsetbit(TIM4_EGR, 0); // update generation + + rsetbit(TIM4_CR1, 3); // one pulse mode + rsetbitsfrom(TIM4_CCMR1, 4, 0x6); // mode + + //rsetbit(TIM4_CCMR1, 3); // preload enable + //rsetbit(TIM4_CR1, 7); // buffered + + rsetbit(TIM4_CCER, 0); // enable output channeli 1 + rsetbit(TIM4_CCER, 1); // active low + rsetbit(TIM4_CR1, 0); // start counter + + /* INTERRUPTS */ + ivt_set_gate(46, tmp_update_handler, 0); + + rsetbit(TIM4_DIER, 1); + rsetbit(NVIC_ISER0, 30); // interupt 41 - 32 + +} + +void tsensor_input(uint16_t preload) { + + //uint16_t timestamp; + /* GPIO AND CLOCK */ + //rsetbit(RCC_APB2ENR, 3); // GPIOB enable + //rwrite(GPIOB_CRL, 0x44444444); // Input floating (default state) + //rsetbit(RCC_APB1ENR, 2); // TIM4 enable + + //rsetbitsfrom(TIM4_CR1, 5, 0x00); // edge-aligned mode + //rclrbit(TIM4_CR1, 4); // upcounter (clrbit! not needed to set) + + rwrite(TIM4_PSC, PRESCALER - 1); // 1 MHz + rwrite(TIM4_ARR, preload); // preload + + + rsetbit(TIM4_EGR, 0); // update generation + + rsetbit(TIM4_CCMR1, 0); // input on TI1 + rsetbit(TIM4_CCMR1, 9); // another input TI2 + rsetbit(TIM4_CCER, 1); // other polarity for T1, inverted + + /* TODO: reg funct */ + rsetbit(TIM4_SMCR, 4); // OLD: 101, new Edge detector + rsetbit(TIM4_SMCR, 6); // + + + // rsetbit(TIM4_SMCR, 2); // RESET rising edge triggers counter and generates update + rsetbit(TIM4_SMCR, 2); // OLD: 110 + rsetbit(TIM4_SMCR, 1); + rsetbit(TIM4_SMCR, 0); + //rsetbit(TIM4_SMCR, 1); // 110 + + //rsetbit(TIM4_CR1, 3); // one pulse mode // NOTE: RESET after finised preload + // will catch multiple signal... can set fram + + rsetbit(TIM4_CCER, 0); // enable capture channel 1 (changed pos) + rsetbit(TIM4_CCER, 4); // enable capture channel 2 + /* Caught on rising edge, no need to change*/ + /* Clear capture event flag */ +// rsetbit(TIM4_CR1, 0); // RESET with no trigger mode start + + // enable capture channel 1 interrupt + rsetbit(TIM4_DIER, 1); + rsetbit(TIM4_DIER, 2); + ivt_set_gate(46, update_handler, 0); + rsetbit(NVIC_ISER0, 30); + +} diff --git a/drivers/uart.c b/drivers/uart.c index 4693c6f..0090ef2 100644 --- a/drivers/uart.c +++ b/drivers/uart.c @@ -10,7 +10,6 @@ #include -#define RXNE ((*USART1_SR >> 5) & 0x1) #define UARTBUF 256 #define ECHO 1 @@ -20,19 +19,16 @@ static struct { uint32_t wpos; } linefeed; +void set_baudrate(); void * uart_handler() { - //uart_puts("echo: "); - while (RXNE) { + while (rchkbit(USART1_SR, 5)) { 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('\n'); } @@ -42,50 +38,42 @@ void uart_init() { linefeed.wpos = 0; //memset(&linefeed, 0, (sizeof(struct linefeed) )); - regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA + //rsetbitsfrom(RCC_APB2ENR, 0, 0x4005); + rsetbit(RCC_APB2ENR, 0); + rsetbit(RCC_APB2ENR, 2); + rsetbit(RCC_APB2ENR, 14); /* (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 TODO: check + rwrite(GPIOA_CRH, 0x444444D4); + // set event control register, output on PA, Pin 9 TODO: check + rsetbitsfrom(AFIO_EVCR, 0, 0x89); //disable temporarily to set values - regw_u8(USART1_CR1, 0x0, 13, SETBIT); + rclrbit(USART1_CR1, 13); - /* baud rate 115200, 8MHz / (16 * USARTDIV) - * USARTDIV = 4.34 - * FRACTION: 16 x 0.34 = 0d5.44 0d5 -> 0x5 - * MANTISSA: 0d4.34 0d4 -> 0x4 - * USART_BRR = 0x45*/ + set_baudrate(); - regw_u32(USART1_BRR, 0x00000045, 0, OWRITE); - regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00 + //set stop bit, default is 1 stop bit 0x00 + rwrite(USART1_CR2, 0x0000); /* 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, OWRITE); + rwrite(USART1_CR1, 0x0000302C); ivt_set_gate(53, uart_handler, 0); - *NVIC_ISER1 = (1 << 5); // Enable UART interrupt at NVIC -} - -static void wait() { - for (int i = 0; i < 100; i++); + rsetbit(NVIC_ISER1, 5); } void uart_putc(unsigned char ch) { if (ch == '\n') { - while (*USART1_SR & 0x0C) { } // transmit data register empty and complete + while(!rchkbit(USART1_SR, 6)); regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line } - - while (*USART1_SR & 0x0C) {} + while(!rchkbit(USART1_SR, 6)); regw_u8(USART1_DR, ch, 0, OWRITE); - - wait(); } char uart_getc(void) { @@ -100,12 +88,24 @@ char uart_getc(void) { return 0; } - -// move to library -/* extern void uart_puts(unsigned char *str) { - int i; - for (i = 0; i < strlen(str); i++) { - uart_putc(str[i]); - } -} */ - +/* Calculate baud rate. Example how this is done + * to set this register on a stm32 + * Desired baudrate: 115200, CLK: 8 MHz + * Desired Baudrate = CLK / (16 * USARTDIV) + * USARTDIV = 4.34 + * FRACTION: 16 x 0.34 = 0d5.44 0d5 -> 0x5 + * MANTISSA: 0d4.34 0d4 -> 0x4 + * USART_BRR = 0x45*/ + +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); +#else + rwrite(USART1_BRR, 0x00000045); +#endif +} diff --git a/include/drivers/at24c.h b/include/drivers/at24c.h new file mode 100644 index 0000000..c5e6026 --- /dev/null +++ b/include/drivers/at24c.h @@ -0,0 +1,21 @@ +#ifndef __AT24C_H +#define __AT24C_H + +/* HELPER SUBROUTINES DECLARATIONS */ +static void start_condition(); +static void stop_condition(); +static int ack_recv(); +static int buf_empty(); +static int data_recv(); +static int late_recv(); +static int delay(); + +extern void eeprom_at24c_init(); +extern int eeprom_write(uint16_t addr, char * data, size_t size); +extern int eeprom_erase(); +extern int eeprom_read(uint16_t addr, int num, char * rvalues); +extern int eeprom_dump(); + +extern int eeprom_test(); + +#endif diff --git a/include/drivers/tsensor.h b/include/drivers/tsensor.h new file mode 100644 index 0000000..ced6f5d --- /dev/null +++ b/include/drivers/tsensor.h @@ -0,0 +1,4 @@ +extern void tsensor_output(uint16_t, uint16_t/* , uint16_t */); +extern void tsensor_input(uint16_t); +extern void run(); + diff --git a/include/lib/regfunc.h b/include/lib/regfunc.h index f194df0..b13c28f 100644 --- a/include/lib/regfunc.h +++ b/include/lib/regfunc.h @@ -1,5 +1,10 @@ /* regfunc.h */ extern char * regtohex(uint32_t ); extern uint32_t hextoreg(char *); +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); diff --git a/include/lib/stdio.h b/include/lib/stdio.h index cf3075b..93d1f99 100644 --- a/include/lib/stdio.h +++ b/include/lib/stdio.h @@ -6,3 +6,4 @@ extern char getchar(); extern void cputchar(char); extern void cputs(unsigned char *); extern char * readline(); +extern void putc(void *, char); diff --git a/include/lib/tinyprintf.h b/include/lib/tinyprintf.h new file mode 100644 index 0000000..8855710 --- /dev/null +++ b/include/lib/tinyprintf.h @@ -0,0 +1,107 @@ +/* +File: tinyprintf.h + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +/* Global configuration */ + +/* Set this to 0 if you do not want to provide tfp_printf */ +#ifndef TINYPRINTF_DEFINE_TFP_PRINTF +# define TINYPRINTF_DEFINE_TFP_PRINTF 1 +#endif + +/* Set this to 0 if you do not want to provide + tfp_sprintf/snprintf/vsprintf/vsnprintf */ +#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF +# define TINYPRINTF_DEFINE_TFP_SPRINTF 1 +#endif + +/* Set this to 0 if you do not want tfp_printf and + tfp_{vsn,sn,vs,s}printf to be also available as + printf/{vsn,sn,vs,s}printf */ +#ifndef TINYPRINTF_OVERRIDE_LIBC +# define TINYPRINTF_OVERRIDE_LIBC 1 +#endif + +/* Optional external types dependencies */ + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +# include /* size_t */ +#endif + +/* Declarations */ + +#ifdef __GNUC__ +# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx) \ + __attribute__((format (printf, fmt_idx, arg1_idx))) +#else +# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*putcf) (void *, char); + +/* + 'tfp_format' really is the central function for all tinyprintf. For + each output character after formatting, the 'putf' callback is + called with 2 args: + - an arbitrary void* 'putp' param defined by the user and + passed unmodified from 'tfp_format', + - the character. + The 'tfp_printf' and 'tfp_sprintf' functions simply define their own + callback and pass to it the right 'putp' it is expecting. +*/ +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va); + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int tfp_snprintf(char *str, size_t size, const char *fmt, ...) \ + _TFP_SPECIFY_PRINTF_FMT(3, 4); +int tfp_vsprintf(char *str, const char *fmt, va_list ap); +int tfp_sprintf(char *str, const char *fmt, ...) \ + _TFP_SPECIFY_PRINTF_FMT(2, 3); +# if TINYPRINTF_OVERRIDE_LIBC +# define vsnprintf tfp_vsnprintf +# define snprintf tfp_snprintf +# define vsprintf tfp_vsprintf +# define sprintf tfp_sprintf +# endif +#endif + +#if TINYPRINTF_DEFINE_TFP_PRINTF +void init_printf(void *putp, putcf putf); +void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); +# if TINYPRINTF_OVERRIDE_LIBC +# define printf tfp_printf +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/mmap.h b/include/sys/mmap.h index a5d2228..9aae914 100644 --- a/include/sys/mmap.h +++ b/include/sys/mmap.h @@ -32,7 +32,10 @@ /* SYSTEM INFO AND DEBUG */ #define MCU_ID MEM_ADDR(0xE000ED00) -#define FLASH_MEM MEM_ADDR(0x1FFFF000) +#define FLASH_MEM MEM_ADDR(0x1FFFF000) + +/* POWER CONTROL REGISTERS */ +#define PWR_CR MEM_ADDR(0x40007000) /* SYSTEM CONTROL BLOCK REGISTER */ #define SCB_VTOR MEM_ADDR(0xE000ED08) // VECTOR TABLE @@ -46,10 +49,12 @@ /* SYSTICK REGISTER */ #define STK_CTRL MEM_ADDR(0xE000E010) #define STK_RELOAD MEM_ADDR(0xE000E014) +#define STK_CALIB MEM_ADDR(0xE000E01C) -/* CLOCK REGISTER */ +/* RESET AND CLOCK REGISTER */ #define RCC_CR MEM_ADDR(0x40021000) #define RCC_CFGR MEM_ADDR(0x40021004) +#define RCC_BDCR MEM_ADDR(0x40021020) /* SYSTEM CONTROL REGISTER */ #define SYSCTRL_RCC MEM_ADDR(0x40021000) @@ -63,9 +68,15 @@ #define GPIOPA_AFSEL MEM_ADDR(0x40004420) #define GPIOA_CRH MEM_ADDR(0x40010804) // for USART1 +#define GPIOA_ODR MEM_ADDR(0x4001080C) #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 GPIOB_BSRR MEM_ADDR(0x40010C10) +#define GPIOC_CRL MEM_ADDR(0x40011000) // led +#define GPIOC_CRH MEM_ADDR(0x40011004) +#define GPIOC_ODR MEM_ADDR(0x4001100C) + +#define GPIOD_CRL MEM_ADDR(0x40011400) +#define GPIOD_ODR MEM_ADDR(0x4001140C) #define AFIO_EVCR MEM_ADDR(0x40010000) @@ -90,3 +101,26 @@ #define USART1_CR1 MEM_ADDR(0x4001380C) #define USART1_CR2 MEM_ADDR(0x40013810) #define USART1_CR3 MEM_ADDR(0x40013814) + +/* REAL TIME CLOCK REGISTERS */ +#define RTC_CRH MEM_ADDR(0x40002800) // interrupts +#define RTC_CRL MEM_ADDR(0x40002804) +#define RTC_PRLL MEM_ADDR(0x4000280C) +#define RTC_CNTH MEM_ADDR(0x40002818) +#define RTC_CNTL MEM_ADDR(0x4000281C) +/* BACKUP (CALIBR) REGISTERS */ +#define BKP_RTCCR MEM_ADDR(0x40006C2C) // RTC Calibration + +#define TIM4_CR1 MEM_ADDR(0x40000800) +#define TIM4_RCR MEM_ADDR(0x40000830) +#define TIM4_ARR MEM_ADDR(0x4000082C) +#define TIM4_EGR MEM_ADDR(0x40000814) +#define TIM4_SR1 MEM_ADDR(0x40000810) +#define TIM4_CCR1 MEM_ADDR(0x40000834) +#define TIM4_CCR2 MEM_ADDR(0x40000838) +#define TIM4_PSC MEM_ADDR(0x40000828) +#define TIM4_SMCR MEM_ADDR(0x40000808) +#define TIM4_CCER MEM_ADDR(0x40000820) +//#define TIM1_BDTR MEM_ADDR(0x40000844) +#define TIM4_CCMR1 MEM_ADDR(0x40000818) +#define TIM4_DIER MEM_ADDR(0x4000080C) diff --git a/include/sys/robsys.h b/include/sys/robsys.h index e02eded..9a19a47 100644 --- a/include/sys/robsys.h +++ b/include/sys/robsys.h @@ -1,8 +1,23 @@ #ifndef __SYSTEM_H #define __SYSTEM_H -/* CLOCK.C */ + +/* CLOCK.C + * Board specific clock settings. These boards often come with two + * external oscillators: one high speed (8MHz) and one low speed (~30kHz). + * These values are used throughout the code to calculator desired baud + * rates etc. + */ +//#define ENABLE_HSE +//efine CRYSTAL_MHZ 8 +//efine CLKSPEED_MHZ 72 extern void clock_init(); +// extern int clock_test(); +// extern void clock_reset(); + +/* RTC.C */ +#define ENABLE_RTC +extern void rtc_init(); /* IVT.C */ extern void ivt_init(); @@ -14,12 +29,6 @@ extern void systick_init(); /* SYSINFO.C */ extern void sysinfo(); -/* MM.C DELETE TODO */ -//extern void mm_init(); -//extern void * malloc(size_t); -//extern void free(void *); -//extern void test_memory(uint32_t *); - /* POOL.c */ extern void pool_init(size_t, unsigned int, uint32_t *); extern void * alloc(); diff --git a/ivt.c b/ivt.c index 9f8e643..02c45ec 100644 --- a/ivt.c +++ b/ivt.c @@ -30,6 +30,7 @@ #include #include #include +#include /* * These values are pushed on the stack just before @@ -92,13 +93,15 @@ char * messages[] = { if (intnr < 20) // TODO: strlen return messages[intnr]; - return NULL; + +return "UNKNOWN"; } void ivt_set_gate(unsigned char num, void * isr(), short pri) { ivt[num] = (uint32_t) isr; - *NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F)); +// if (num <= 32) +// *NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F)); /* TODO: Priorities */ } @@ -106,16 +109,23 @@ void ivt_set_gate(unsigned char num, void * isr(), short pri) { /* Dummy interrupt: comment out the comment to use a naked * function */ -// __attribute__ ((interrupt)) -void * dummy_isr(/* struct interrupt_frame * frame */) { +__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); + printf("R1:%p\n",frame->r1); + printf("R2:%p\n",frame->r2); + printf("R3:%p\n",frame->r3); + printf("R12:%p\n",frame->r12); + printf("LR:%p\n",frame->lr); + printf("PC:%p\n",frame->pc); + printf("PSR:%p\n",frame->psr); - cputs("EXCEPTION: "); - cputs(exception_message(nr)); - cputs("\nSYSTEM HALTED\n"); - - for(;;); + //for(;;); } /* Initialize interrupt vector */ diff --git a/lib/regfunc.c b/lib/regfunc.c index b783901..9ea7d7b 100644 --- a/lib/regfunc.c +++ b/lib/regfunc.c @@ -8,6 +8,34 @@ #include + +// register set bit at position +void rsetbit(volatile uint32_t * reg, short pos) { + *reg = *reg | (0x1 << pos); +} + +// register set bits from certain pos +void rsetbitsfrom(volatile uint32_t * reg, short pos, int val) { + *reg = *reg | (val << pos); +} + +// register clear bit at position +void rclrbit(volatile uint32_t * reg, short pos) { + *reg = *reg & ~(0x1 << pos); +} + +int rchkbit(volatile uint32_t * reg, short pos) { + if ((*reg >> pos) & 0x1) + return 1; + return 0; +} + +// register (over)write +void rwrite(volatile uint32_t * reg, uint32_t val) { + *reg = val; +} + + /* write value (uint8_t) to register */ void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { @@ -19,7 +47,7 @@ void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { *reg = *reg | (val << shift); break; case CLRBIT: - *reg = (val << shift); + *reg = *reg & ~(val << shift); break; } } @@ -35,6 +63,7 @@ void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) { *reg = *reg | (val << shift); break; case CLRBIT: + *reg = *reg & ~(val << shift); break; } } diff --git a/lib/stdio.c b/lib/stdio.c index ac26165..9ef20ee 100644 --- a/lib/stdio.c +++ b/lib/stdio.c @@ -31,6 +31,12 @@ void cputchar(char c) { } +void putc(void *p, char c) { + + cputchar(c); + +} + void cputs(unsigned char *str) { int i; diff --git a/lib/tinyprintf.c b/lib/tinyprintf.c new file mode 100644 index 0000000..d57128f --- /dev/null +++ b/lib/tinyprintf.c @@ -0,0 +1,521 @@ +/* +File: tinyprintf.c + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include + + +/* + * Configuration + */ + +/* Enable long int support */ +#define PRINTF_LONG_SUPPORT + +/* Enable long long int support (implies long int support) */ +//#define PRINTF_LONG_LONG_SUPPORT + +/* Enable %z (size_t) support */ +#define PRINTF_SIZE_T_SUPPORT + +/* + * Configuration adjustments + */ +#ifdef PRINTF_SIZE_T_SUPPORT +#include +#endif + +#ifdef PRINTF_LONG_LONG_SUPPORT +# define PRINTF_LONG_SUPPORT +#endif + +/* __SIZEOF___ defined at least by gcc */ +#ifdef __SIZEOF_POINTER__ +# define SIZEOF_POINTER __SIZEOF_POINTER__ +#endif +#ifdef __SIZEOF_LONG_LONG__ +# define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__ +#endif +#ifdef __SIZEOF_LONG__ +# define SIZEOF_LONG __SIZEOF_LONG__ +#endif +#ifdef __SIZEOF_INT__ +# define SIZEOF_INT __SIZEOF_INT__ +#endif + +#ifdef __GNUC__ +# define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline)) +#else +# define _TFP_GCC_NO_INLINE_ +#endif + +/* + * Implementation + */ +struct param { + char lz:1; /**< Leading zeros */ + char alt:1; /**< alternate form */ + char uc:1; /**< Upper case (for base16 only) */ + char align_left:1; /**< 0 == align right (default), 1 == align left */ + unsigned int width; /**< field width */ + char sign; /**< The sign to display (if any) */ + unsigned int base; /**< number base (e.g.: 8, 10, 16) */ + char *bf; /**< Buffer to output */ +}; + + +#ifdef PRINTF_LONG_LONG_SUPPORT +static void _TFP_GCC_NO_INLINE_ ulli2a( + unsigned long long int num, struct param *p) +{ + int n = 0; + unsigned long long int d = 1; + char *bf = p->bf; + while (num / d >= p->base) + d *= p->base; + while (d != 0) { + int dgt = num / d; + num %= d; + d /= p->base; + if (n || dgt > 0 || d == 0) { + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + ++n; + } + } + *bf = 0; +} + +static void lli2a(long long int num, struct param *p) +{ + if (num < 0) { + num = -num; + p->sign = '-'; + } + ulli2a(num, p); +} +#endif + +#ifdef PRINTF_LONG_SUPPORT +static void uli2a(unsigned long int num, struct param *p) +{ + int n = 0; + unsigned long int d = 1; + char *bf = p->bf; + while (num / d >= p->base) + d *= p->base; + while (d != 0) { + int dgt = num / d; + num %= d; + d /= p->base; + if (n || dgt > 0 || d == 0) { + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + ++n; + } + } + *bf = 0; +} + +static void li2a(long num, struct param *p) +{ + if (num < 0) { + num = -num; + p->sign = '-'; + } + uli2a(num, p); +} +#endif + +static void ui2a(unsigned int num, struct param *p) +{ + int n = 0; + unsigned int d = 1; + char *bf = p->bf; + while (num / d >= p->base) + d *= p->base; + while (d != 0) { + int dgt = num / d; + num %= d; + d /= p->base; + if (n || dgt > 0 || d == 0) { + *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10); + ++n; + } + } + *bf = 0; +} + +static void i2a(int num, struct param *p) +{ + if (num < 0) { + num = -num; + p->sign = '-'; + } + ui2a(num, p); +} + +static int a2d(char ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static char a2u(char ch, const char **src, int base, unsigned int *nump) +{ + const char *p = *src; + unsigned int num = 0; + int digit; + while ((digit = a2d(ch)) >= 0) { + if (digit > base) + break; + num = num * base + digit; + ch = *p++; + } + *src = p; + *nump = num; + return ch; +} + +static void putchw(void *putp, putcf putf, struct param *p) +{ + char ch; + int n = p->width; + char *bf = p->bf; + + /* Number of filling characters */ + while (*bf++ && n > 0) + n--; + if (p->sign) + n--; + if (p->alt && p->base == 16) + n -= 2; + else if (p->alt && p->base == 8) + n--; + + /* Fill with space to align to the right, before alternate or sign */ + if (!p->lz && !p->align_left) { + while (n-- > 0) + putf(putp, ' '); + } + + /* print sign */ + if (p->sign) + putf(putp, p->sign); + + /* Alternate */ + if (p->alt && p->base == 16) { + putf(putp, '0'); + putf(putp, (p->uc ? 'X' : 'x')); + } else if (p->alt && p->base == 8) { + putf(putp, '0'); + } + + /* Fill with zeros, after alternate or sign */ + if (p->lz) { + while (n-- > 0) + putf(putp, '0'); + } + + /* Put actual buffer */ + bf = p->bf; + while ((ch = *bf++)) + putf(putp, ch); + + /* Fill with space to align to the left, after string */ + if (!p->lz && p->align_left) { + while (n-- > 0) + putf(putp, ' '); + } +} + +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va) +{ + struct param p; +#ifdef PRINTF_LONG_SUPPORT + char bf[23]; /* long = 64b on some architectures */ +#else + char bf[12]; /* int = 32b on some architectures */ +#endif + char ch; + p.bf = bf; + + while ((ch = *(fmt++))) { + if (ch != '%') { + putf(putp, ch); + } else { +#ifdef PRINTF_LONG_SUPPORT + char lng = 0; /* 1 for long, 2 for long long */ +#endif + /* Init parameter struct */ + p.lz = 0; + p.alt = 0; + p.width = 0; + p.align_left = 0; + p.sign = 0; + + /* Flags */ + while ((ch = *(fmt++))) { + switch (ch) { + case '-': + p.align_left = 1; + continue; + case '0': + p.lz = 1; + continue; + case '#': + p.alt = 1; + continue; + default: + break; + } + break; + } + + /* Width */ + if (ch >= '0' && ch <= '9') { + ch = a2u(ch, &fmt, 10, &(p.width)); + } + + /* We accept 'x.y' format but don't support it completely: + * we ignore the 'y' digit => this ignores 0-fill + * size and makes it == width (ie. 'x') */ + if (ch == '.') { + p.lz = 1; /* zero-padding */ + /* ignore actual 0-fill size: */ + do { + ch = *(fmt++); + } while ((ch >= '0') && (ch <= '9')); + } + +#ifdef PRINTF_SIZE_T_SUPPORT +# ifdef PRINTF_LONG_SUPPORT + if (ch == 'z') { + ch = *(fmt++); + if (sizeof(size_t) == sizeof(unsigned long int)) + lng = 1; +# ifdef PRINTF_LONG_LONG_SUPPORT + else if (sizeof(size_t) == sizeof(unsigned long long int)) + lng = 2; +# endif + } else +# endif +#endif + +#ifdef PRINTF_LONG_SUPPORT + if (ch == 'l') { + ch = *(fmt++); + lng = 1; +#ifdef PRINTF_LONG_LONG_SUPPORT + if (ch == 'l') { + ch = *(fmt++); + lng = 2; + } +#endif + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u': + p.base = 10; +#ifdef PRINTF_LONG_SUPPORT +#ifdef PRINTF_LONG_LONG_SUPPORT + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'd': + case 'i': + p.base = 10; +#ifdef PRINTF_LONG_SUPPORT +#ifdef PRINTF_LONG_LONG_SUPPORT + if (2 == lng) + lli2a(va_arg(va, long long int), &p); + else +#endif + if (1 == lng) + li2a(va_arg(va, long int), &p); + else +#endif + i2a(va_arg(va, int), &p); + putchw(putp, putf, &p); + break; +#ifdef SIZEOF_POINTER + case 'p': + p.alt = 1; +# if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT + lng = 0; +# elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG + lng = 1; +# elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG + lng = 2; +# endif +#endif + case 'x': + case 'X': + p.base = 16; + p.uc = (ch == 'X')?1:0; +#ifdef PRINTF_LONG_SUPPORT +#ifdef PRINTF_LONG_LONG_SUPPORT + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else +#endif + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else +#endif + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'o': + p.base = 8; + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'c': + putf(putp, (char)(va_arg(va, int))); + break; + case 's': + p.bf = va_arg(va, char *); + putchw(putp, putf, &p); + p.bf = bf; + break; + case '%': + putf(putp, ch); + default: + break; + } + } + } + abort:; +} + +#if TINYPRINTF_DEFINE_TFP_PRINTF +static putcf stdout_putf; +static void *stdout_putp; + +void init_printf(void *putp, putcf putf) +{ + stdout_putf = putf; + stdout_putp = putp; +} + +void tfp_printf(char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + tfp_format(stdout_putp, stdout_putf, fmt, va); + va_end(va); +} +#endif + +#if TINYPRINTF_DEFINE_TFP_SPRINTF +struct _vsnprintf_putcf_data +{ + size_t dest_capacity; + char *dest; + size_t num_chars; +}; + +static void _vsnprintf_putcf(void *p, char c) +{ + struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p; + if (data->num_chars < data->dest_capacity) + data->dest[data->num_chars] = c; + data->num_chars ++; +} + +int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + struct _vsnprintf_putcf_data data; + + if (size < 1) + return 0; + + data.dest = str; + data.dest_capacity = size-1; + data.num_chars = 0; + tfp_format(&data, _vsnprintf_putcf, format, ap); + + if (data.num_chars < data.dest_capacity) + data.dest[data.num_chars] = '\0'; + else + data.dest[data.dest_capacity] = '\0'; + + return data.num_chars; +} + +int tfp_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsnprintf(str, size, format, ap); + va_end(ap); + return retval; +} + +struct _vsprintf_putcf_data +{ + char *dest; + size_t num_chars; +}; + +static void _vsprintf_putcf(void *p, char c) +{ + struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p; + data->dest[data->num_chars++] = c; +} + +int tfp_vsprintf(char *str, const char *format, va_list ap) +{ + struct _vsprintf_putcf_data data; + data.dest = str; + data.num_chars = 0; + tfp_format(&data, _vsprintf_putcf, format, ap); + data.dest[data.num_chars] = '\0'; + return data.num_chars; +} + +int tfp_sprintf(char *str, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = tfp_vsprintf(str, format, ap); + va_end(ap); + return retval; +} +#endif diff --git a/main.c b/main.c index 342059e..8455b46 100644 --- a/main.c +++ b/main.c @@ -19,20 +19,58 @@ #include #include +#include #include #include #include +#include +#include + +//void sleep() { +// +// __asm__ __volatile__("wfe"); +// +//} void main() { + clock_init(); ivt_init(); uart_init(); // cputs("ROBSYS LOADING...\n"); - systick_init(); - led_init(); + //systick_init(); +// tsensor_output(0xFFFF, 0x7FFF); + + 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"); */ sysinfo(); + +// tsensor_input(5000); +// run(); + + led_init(); +// eeprom_at24c_init(); +// eeprom_test(); +// rtc_init(); + tm1637_init(); tm1637_start(); diff --git a/rtc.c b/rtc.c new file mode 100644 index 0000000..4877d92 --- /dev/null +++ b/rtc.c @@ -0,0 +1,92 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/30 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * + * */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include + + +static void periodic_intr() { + + while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated + rsetbit(RTC_CRL, 4); // start configure + + rsetbit(RTC_CRH, 0); // enable periodic (second) interrupt + + while(!rchkbit(RTC_CRL, 5)); + + rwrite(RTC_PRLL, 0x7FFF); // 1 second + rclrbit(RTC_CRL, 4); // stop configure + while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated + rsetbit(NVIC_ISER0, 3); // enable in register vector +} + +static void calibrate_rtc() { + + +// rsetbit(BKP_RTCCR, 7); // enable CC0, +// while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated +// rsetbit(RTC_CRL, 4); + + // Set up and check tamper pin + +// rclrbit(RTC_CRL, 4); +// while(!rchkbit(RTC_CRL, 5)); // Check last write is terminated +} + +void * rtc_handler() { + + //cputs("TICKING IN REAL TIME\n"); + //uint32_t curr = *RTC_CNTL; + int even = *RTC_CNTL % 2; + (!even) ? led_off() : led_on(); + + rclrbit(RTC_CRL, 0); +} + +static void setup_rtc() { + +// TODO: long time to get stable? + /* Enable PWREN and BKPEN */ + rsetbit(RCC_APB1ENR, 28); + rsetbit(RCC_APB1ENR, 27); + + /* Enable access to backup registers and RTC */ + rsetbit(PWR_CR, 8); + + rsetbit(RCC_BDCR, 0); /* LSE enable */ + while(!rchkbit(RCC_BDCR, 1)); /* wait for LSE to come up */ + + rsetbitsfrom(RCC_BDCR, 8, 0x1); /* use LSE as RTC source */ + rsetbit(RCC_BDCR, 15); /* enable RTC */ + + ivt_set_gate(19, rtc_handler, 0); /* setup interrupt handler */ + +// calibrate_rtc(); TODO: TAMPER PIN? + + periodic_intr();// setup periodic interrupt + +} + +void rtc_init() { + +#ifdef ENABLE_RTC + setup_rtc(); +#endif + +} diff --git a/sysinfo.c b/sysinfo.c index 7f06334..bd5d1bb 100644 --- a/sysinfo.c +++ b/sysinfo.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include @@ -22,28 +22,28 @@ uint32_t get_msp(void); void sysinfo() { uint32_t tmp = *MCU_ID; - cputs("# DEVICE ID: "); + printf("# DEVICE ID: "); if (tmp & 0x414) - cputs("HIGH DENSITY\n"); + printf("HIGH DENSITY\n"); else { - cputs("UNKNOWN\n"); + printf("UNKNOWN\n"); } tmp = (tmp >> 16); - cputs("# REVISION: "); + printf("# REVISION: "); switch (tmp) { case 0x1000: - cputs("REVISION A\n"); + printf("REVISION A\n"); break; case 0x1001: - cputs("REVISION Z\n"); + printf("REVISION Z\n"); break; case 0x1003: - cputs("REVISION 1/2/3/X/Y\n"); + printf("REVISION 1/2/3/X/Y\n"); break; default: - cputs("UNKNOWN\n"); + printf("UNKNOWN\n"); } extern char _endofbss; @@ -53,15 +53,15 @@ void sysinfo() { uint32_t data_bss = &_endofbss - SRAM_OFFSET; uint32_t mem_free = SRAM_SIZE - stack_usage - data_bss; - cputs("# TOTAL MEMORY: "); - cputs(regtohex(SRAM_SIZE)); - cputchar('\n'); - cputs("# FREE MEMORY: "); - cputs(regtohex(mem_free)); - cputchar('\n'); - cputs("# STACK USAGE: "); - cputs(regtohex(stack_usage)); - cputchar('\n'); + 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 1d632ec..05f515f 100644 --- a/systick.c +++ b/systick.c @@ -5,7 +5,8 @@ #include #include -#include // TODO +#include +#include struct interrupt_frame { @@ -22,25 +23,31 @@ struct interrupt_frame { //__attribute__ ((interrupt)) void * systick_handler(/* struct interrupt_frame * frame */) { -// uint32_t volatile status; - //uart_puts("TICKING\n"); +// cputs("TICKING\n"); // for(;;); } void systick_init() { - /* Enable the counter and enable the interrupt - * associated with it */ - *STK_CTRL = (volatile uint32_t) 0x00000003; - - /* The counter reload register here holds - * 0x1000 -- that's 4096 clock cycles -- if - * it is down to zero it is restores the value */ - *STK_RELOAD = (volatile uint32_t) 0x00400000; - /* Every time the counter counts down to zero * a systick exception is asserted. Systick has * exception number 15. in the vector table */ ivt_set_gate(15, systick_handler, 0); + + /* Get calibration and set this to 1 sec + * !Most boards have a 1 ms or 10 ms + * calibration value */ + int calib = (*STK_CALIB << 0) * 500; + + /* The counter reload registers counts down to zero + * and then it is restores the value */ + rwrite(STK_RELOAD, calib); + + /* Enable the counter and enable the interrupt + * associated with it */ + rsetbit(STK_CTRL, 0); + rsetbit(STK_CTRL, 1); + + } diff --git a/term.c b/term.c index 51eb9cf..7ce25ce 100644 --- a/term.c +++ b/term.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -15,14 +16,15 @@ #define BUFSIZE 200 #define MAXARGS 5 #define WHITESPACE "\t\r\n " -#define BUILTINCMDS 3 +#define BUILTINCMDS 4 int help(int, char**); /* * Built in commands * info -- shows basic info of system - * reset -- software reset + * uptime -- uptime; read from the RTC register + * reset -- software reset TODO * show [ADDRESS-ADDRESS] -- shows SRAM range * switchmode -- switch to unprivileged mode * */ @@ -37,11 +39,18 @@ struct cmd { struct cmd builtincmds[4]; -int help(int argc, char ** argsv) { +int info(int argc, char ** argsv) { sysinfo(); return 0; } +int uptime(int arg, char ** argsv) { + //cputs("CURRENT UPTIME: "); + //cputs(regtohex(*RTC_CNTL)); + //cputchar('\n'); + printf("CURRENT UPTIME: %p\n", *RTC_CNTL); +} + int led(int argc, char ** argsv) { @@ -116,8 +125,8 @@ int exec_cmd(char * buf) { void terminal() { - builtincmds[0].name = "help"; - builtincmds[0].function = help; + builtincmds[0].name = "info"; + builtincmds[0].function = info; builtincmds[1].name = "led"; builtincmds[1].function = led; @@ -125,8 +134,12 @@ void terminal() { builtincmds[2].name = "show"; builtincmds[2].function = show; + builtincmds[3].name = "uptime"; + builtincmds[3].function = uptime; + + char *buf; - cputs("WELCOME TO ROBSYS!\n"); + //cputs("WELCOME TO ROBSYS!\n"); while (1) { buf = readline("root# ");