b370294305895067ef2ac230c3d5de55176d77fa
[cortex-from-scratch] / drivers / uart.c
1 #include <stdbool.h>
2 #include <stddef.h>
3 #include <stdint.h>
4
5 #include <sys/mmap.h>
6 #include <sys/robsys.h>
7
8 #include <lib/regfunc.h>
9 #include <lib/string.h>
10
11 #include <drivers/uart.h>
12
13 #define RXNE ((*USART1_SR >> 5) & 0x1)
14 #define UARTBUF 256
15 #define ECHO 1
16
17 static struct {
18          uint8_t buf[UARTBUF];
19          uint32_t rpos;
20          uint32_t wpos;
21 } linefeed;
22
23 void set_baudrate();
24
25 void * uart_handler() {
26
27         //uart_puts("echo: ");
28         while (RXNE) {
29                 char echochar = *USART1_DR;
30 //              uart_putc(echochar);
31                 linefeed.buf[linefeed.wpos++] = echochar;
32                  if (linefeed.wpos == UARTBUF)
33                          linefeed.wpos = 0;
34                 //regw_u32(USART1_DR, echochar, 0, O_WRITE);
35         }
36         //uart_putc('\n');
37                 
38 }
39
40 void uart_init() {
41
42         linefeed.rpos = 0; 
43         linefeed.wpos = 0;
44
45         //memset(&linefeed, 0, (sizeof(struct linefeed) ));
46         regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA
47         
48         /* (after enable GPIOA), on PA9&PA10 and set mode
49          *  to alternative output */
50         regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE);
51         regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 TODO: check
52
53         //disable temporarily to set values
54         regw_u8(USART1_CR1, 0x0, 13, SETBIT);
55
56         set_baudrate();
57
58         regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00
59         
60         /* parity = 8 bit, UART1 enabled,
61          * TX and RX enabled, interrupts enabled */
62         //regw_u32(USART1_CR1, 0x000030AC, 0, O_WRITE);
63         regw_u32(USART1_CR1, 0x0000302C, 0, OWRITE);
64
65         ivt_set_gate(53, uart_handler, 0);
66         
67         *NVIC_ISER1 = (1 << 5); // Enable UART interrupt at NVIC
68 }
69
70 static void wait() {
71         for (int i = 0; i < 400; i++);
72 }
73
74 void uart_putc(unsigned char ch) {
75         
76         if (ch == '\n') {
77                 while (*USART1_SR & 0x0C) { } // transmit data register empty and complete
78                 regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line
79         }
80
81         while (*USART1_SR & 0x0C) {} 
82                 regw_u8(USART1_DR, ch, 0, OWRITE);
83
84         wait();
85 }
86
87 char uart_getc(void) {
88          char c;
89
90          if (linefeed.rpos != linefeed.wpos) {
91                  c = linefeed.buf[linefeed.rpos++];
92                  if (linefeed.rpos == UARTBUF)
93                          linefeed.rpos = 0;
94                  return c;
95          }
96          return 0;
97  }
98
99 /* Calculate baud rate. Example how this is done
100  * to set this register on a stm32
101  * Desired baudrate: 115200,  CLK: 8 MHz
102  * Desired Baudrate = CLK / (16 * USARTDIV)
103  * USARTDIV = 4.34
104  * FRACTION: 16 x 0.34 = 0d5.44 0d5 -> 0x5
105  * MANTISSA: 0d4.34 0d4 -> 0x4 
106  * USART_BRR = 0x45*/
107         
108 void set_baudrate() {
109
110 //      rwrite(USART1_BRR, 0x000001A1); 48 MHZ
111 //      rwrite(USART1_BRR, 0x0000022B); 64 MHz
112 //      rwrite(USART1_BRR, 0x00000138); 36 MHz
113 //      rwrite(USART1_BRR, 0x00000271); 72 MHz
114 #ifdef ENABLE_HSE
115         rwrite(USART1_BRR, 0x00000138);
116 #else
117         rwrite(USART1_BRR, 0x00000045);
118 #endif
119 }