├── ldscripts ├── libs.ld ├── mem.ld └── sections.ld ├── src ├── buffers.c ├── slcan_config.c ├── led.c ├── systick-utils.c ├── debug_uart.c ├── main.c ├── usart.c ├── can.c └── slcan_shell.c ├── include ├── slcan_config.h ├── usart.h ├── systick-utils.h ├── can.h ├── led.h ├── debug_uart.h ├── buffers.h ├── slcan_shell.h └── stm32f10x_conf.h └── README.md /ldscripts/libs.ld: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Placeholder to list other libraries required by the application. 4 | 5 | GROUP( 6 | ) 7 | 8 | */ 9 | -------------------------------------------------------------------------------- /src/buffers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Placeholders of the buffers used in this application. 5 | * 6 | * buffers.c 7 | * 8 | * Created on: Jun 7, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include "buffers.h" 25 | 26 | can_buf_t can_rx_buf; 27 | uart_in_buf_t uart_in_buf; 28 | uart_str_buf uart_out; 29 | -------------------------------------------------------------------------------- /ldscripts/mem.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory Spaces Definitions. 3 | * 4 | * Need modifying for a specific board. 5 | * FLASH.ORIGIN: starting address of flash 6 | * FLASH.LENGTH: length of flash 7 | * RAM.ORIGIN: starting address of RAM bank 0 8 | * RAM.LENGTH: length of RAM bank 0 9 | * 10 | * The values below can be addressed in further linker scripts 11 | * using functions like 'ORIGIN(RAM)' or 'LENGTH(RAM)'. 12 | */ 13 | 14 | MEMORY 15 | { 16 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K 17 | CCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0 18 | FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K 19 | FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 20 | EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 21 | EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 22 | EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 23 | EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 24 | MEMORY_ARRAY (xrw) : ORIGIN = 0x00000000, LENGTH = 0 25 | } 26 | 27 | /* 28 | * For external ram use something like: 29 | 30 | RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 20K 31 | 32 | */ 33 | -------------------------------------------------------------------------------- /include/slcan_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Adds configurable values. 5 | * 6 | * slcan_config.h 7 | * 8 | * Created on: Jun 6, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #ifndef SLCAN_CONFIG_H_ 25 | #define SLCAN_CONFIG_H_ 26 | 27 | extern uint32_t cfg_can_mode; 28 | extern uint32_t cfg_can_sjw_quanta; 29 | extern uint32_t cfg_can_ts1_quanta; 30 | extern uint32_t cfg_can_ts2_quanta; 31 | extern uint32_t cfg_can_prescaler; 32 | 33 | #endif /* SLCAN_CONFIG_H_ */ 34 | -------------------------------------------------------------------------------- /src/slcan_config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Adds configurable values. 5 | * 6 | * slcan_config.c 7 | * 8 | * Created on: Jun 6, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include "stm32f10x.h" 25 | #include "slcan_config.h" 26 | 27 | /********** Hard-coded, adjustment TBD ***********/ 28 | 29 | uint32_t cfg_can_mode = 0; // Normal mode 30 | uint32_t cfg_can_sjw_quanta = 0; // 1q 31 | uint32_t cfg_can_ts1_quanta = 0x00020000; // 3 tq 32 | uint32_t cfg_can_ts2_quanta = 0x00400000; // 5 tq 33 | uint32_t cfg_can_prescaler = 0x03; // 1 Mbit/s 34 | 35 | -------------------------------------------------------------------------------- /include/usart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device 3 | * 4 | * Implements USART printing via DMA and non-blocking reading. 5 | * 6 | * usart.h 7 | * 8 | * Created on: June 5, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include 25 | 26 | #ifndef USART_H_ 27 | #define USART_H_ 28 | 29 | void init_usart(uint32_t); 30 | 31 | void set_baud_rate(uint32_t baud_rate); 32 | 33 | void write_usart(const char*, int32_t); 34 | 35 | void start_tx_usart(const char*, int32_t); 36 | 37 | uint32_t is_sending(void); 38 | 39 | int read_usart_nonblock(char *c); 40 | 41 | #endif /* USART_H_ */ 42 | -------------------------------------------------------------------------------- /include/systick-utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Implements timestamp handling for incoming CAN messages and miliseconds counters. 5 | * 6 | * systick-utils.h 7 | * 8 | * Created on: Jun 7, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #ifndef SYSTICK_UTILS_H 25 | #define SYSTICK_UTILS_H 26 | 27 | #define F_CPU 72000000UL 28 | #define TIMER_TICK F_CPU/1000-1 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | #include "stm32f10x.h" 35 | 36 | void init_systick_utils(void); 37 | 38 | uint32_t millis(void); 39 | 40 | uint32_t can_timestamp(void); 41 | 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/can.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Implements CAN bus initialization and reading via interrupt. 5 | * 6 | * can.h 7 | * 8 | * Created on: Jun 6, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #ifndef CAN_H_ 25 | #define CAN_H_ 26 | 27 | #define CAN_RX_DMA DMA1 28 | #define CAN_RX_DMA_CH DMA1_Channel1 29 | #define CAN_RX_DMA_CLK RCC_AHBENR_DMA1EN 30 | #define CAN_RX_DMA_IFCR_CLEAR (DMA_ISR_GIF1 | DMA_ISR_TCIF1 | DMA_ISR_HTIF1 | DMA_ISR_TEIF1) 31 | #define CAN_RX_DMA_TX_FLAG DMA_ISR_TCIF1 32 | #define CAN_RX_DMA_IRQ_H DMA1_Channel1_IRQHandler 33 | #define CAN_RX_DMA_IRQ DMA1_Channel1_IRQn 34 | 35 | int open_can(); 36 | 37 | void close_can(); 38 | 39 | #endif /* CAN_H_ */ 40 | -------------------------------------------------------------------------------- /include/led.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Adds some blinky indication of what's going on 5 | * 6 | * led.h 7 | * 8 | * Created on: Jun 8, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #ifndef LED_H_ 25 | #define LED_H_ 26 | 27 | #include "stm32f10x.h" 28 | 29 | #define LED_PORT GPIOA 30 | #define LED_RED GPIO_BRR_BR15 31 | #define LED_GREEN GPIO_BRR_BR12 32 | #define LED_BLUE GPIO_BRR_BR11 33 | 34 | #define LED_ON(led) LED_PORT->BSRR |= led 35 | #define LED_OFF(led) LED_PORT->BRR |= led 36 | 37 | #define LED_PORT_INIT \ 38 | RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; \ 39 | LED_PORT->CRH &= ~(GPIO_CRH_CNF11 | GPIO_CRH_MODE11 | GPIO_CRH_CNF12 | GPIO_CRH_MODE12 | GPIO_CRH_CNF15 | GPIO_CRH_MODE15); \ 40 | LED_PORT->CRH |= (GPIO_CRH_MODE11 | GPIO_CRH_MODE12 | GPIO_CRH_MODE15); 41 | 42 | void blink_green(); 43 | 44 | void blink_blue(); 45 | 46 | void handle_red_blink(); 47 | 48 | void handle_green_blink(); 49 | 50 | void handle_blue_blink(); 51 | 52 | 53 | #endif /* LED_H_ */ 54 | -------------------------------------------------------------------------------- /include/debug_uart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Adds debugging capabilities on spare USART (USART3 in this case) 5 | * 6 | * debug_uart.h 7 | * 8 | * Created on: Jun 10, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #ifndef DEBUG_UART_H_ 25 | #define DEBUG_UART_H_ 26 | 27 | #include "stm32f10x.h" 28 | 29 | #define DBG_BUF_LEN 128 30 | 31 | extern char dbg_buf[DBG_BUF_LEN]; 32 | 33 | #define DBG_UART USART3 34 | #define DBG_UART_BRR 0x0138 // 115200 35 | #define DBG_UART_EN RCC->APB1ENR |= RCC_APB1ENR_USART3EN 36 | #define DBG_UART_IO_EN RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; 37 | #define DBG_UART_IO_CLEAR \ 38 | GPIOB->CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_MODE10 | GPIO_CRH_CNF11 | GPIO_CRH_MODE11) 39 | #define DBG_UART_IO_CFG \ 40 | GPIOB->CRH |= GPIO_CRH_CNF10_1 | GPIO_CRH_MODE10 | GPIO_CRH_CNF11_0 41 | 42 | 43 | #define DWT_CTRL (*(uint32_t*) 0xE0001000) 44 | #define DWT_CYCCNT (*(uint32_t*) 0xE0001004) 45 | 46 | 47 | void open_dbg_uart(void); 48 | 49 | int32_t dbg_print(const char *str); 50 | 51 | int32_t dbg_print_buf(); 52 | 53 | #endif /* DEBUG_UART_H_ */ 54 | -------------------------------------------------------------------------------- /src/led.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Adds some blinky indication of what's going on 5 | * 6 | * led.c 7 | * 8 | * Created on: Jun 8, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include "led.h" 25 | #include "systick-utils.h" 26 | 27 | 28 | static volatile int32_t green_on = 0; 29 | static volatile int32_t blue_on = 0; 30 | 31 | 32 | void blink_green() 33 | { 34 | green_on = 3; 35 | } 36 | 37 | void blink_blue() 38 | { 39 | blue_on = 3; 40 | } 41 | 42 | void handle_red_blink() 43 | { 44 | static uint32_t cm = 0; 45 | static int32_t on = 0; 46 | 47 | if (millis() - cm > 500) { 48 | cm = millis(); 49 | if (on) { 50 | LED_ON(LED_RED); 51 | } else { 52 | LED_OFF(LED_RED); 53 | } 54 | on = !on; 55 | } 56 | } 57 | 58 | void handle_green_blink() 59 | { 60 | static int32_t on = 0; 61 | static uint32_t cm = 0; 62 | 63 | if (millis() - cm > 50) { 64 | cm = millis(); 65 | if (green_on) { 66 | if (on) { 67 | LED_ON(LED_GREEN); 68 | } else { 69 | LED_OFF(LED_GREEN); 70 | green_on--; 71 | } 72 | on = !on; 73 | } 74 | } 75 | } 76 | 77 | void handle_blue_blink() // Not used (yet) 78 | { 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/systick-utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Implements timestamp handling for incoming CAN messages and miliseconds counters. 5 | * 6 | * systick-utils.c 7 | * 8 | * Created on: Jun 7, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | #include "systick-utils.h" 24 | 25 | // As per Lawicel, CAN timestamp overflows every minute and that's enough for most applications. Ok, whatever. 26 | #define CAN_RX_OVF 60000 27 | 28 | static volatile uint32_t miliseconds; 29 | static volatile uint32_t can_rx_ts; 30 | 31 | void SysTick_Handler(void) 32 | { 33 | miliseconds++; 34 | if (++can_rx_ts >= CAN_RX_OVF) { 35 | can_rx_ts = 0; 36 | } 37 | } 38 | 39 | void init_systick_utils(void) 40 | { 41 | miliseconds = 0; 42 | can_rx_ts = 0; 43 | 44 | SysTick->LOAD=TIMER_TICK; 45 | NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); 46 | SysTick->VAL=0UL; 47 | SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk | 48 | SysTick_CTRL_TICKINT_Msk | 49 | SysTick_CTRL_ENABLE_Msk; 50 | } 51 | 52 | uint32_t millis(void) 53 | { 54 | return miliseconds; 55 | } 56 | 57 | uint32_t can_timestamp(void) 58 | { 59 | return can_rx_ts; 60 | } 61 | -------------------------------------------------------------------------------- /src/debug_uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Adds debugging capabilities on spare USART (USART3 in this case) 5 | * 6 | * debug_uart.c 7 | * 8 | * Created on: Jun 10, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include "debug_uart.h" 25 | 26 | char dbg_buf[DBG_BUF_LEN]; 27 | 28 | void open_dbg_uart(void) 29 | { 30 | RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; 31 | DBG_UART_EN; 32 | DBG_UART_IO_EN 33 | DBG_UART_IO_CLEAR; 34 | DBG_UART_IO_CFG; 35 | 36 | DBG_UART->CR1 = 0; 37 | DBG_UART->CR2 = 0; 38 | DBG_UART->CR3 = 0; 39 | DBG_UART->CR1 |= USART_CR1_UE | USART_CR1_RE | USART_CR1_TE; 40 | DBG_UART->BRR = DBG_UART_BRR; 41 | 42 | // Enable debug registers for profiling 43 | if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) { 44 | CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 45 | DWT_CYCCNT = 0; 46 | DWT_CTRL |= 0x01; 47 | } 48 | } 49 | 50 | int32_t dbg_print(const char *str) 51 | { 52 | int32_t i = 0; 53 | while (*str) { 54 | // Write a character to the USART 55 | DBG_UART->DR = (*str & USART_DR_DR); 56 | 57 | while(!(DBG_UART->SR & USART_SR_TXE)); 58 | 59 | i++; 60 | str++; 61 | } 62 | return i; 63 | } 64 | 65 | int32_t dbg_print_buf() 66 | { 67 | return dbg_print(dbg_buf); 68 | } 69 | -------------------------------------------------------------------------------- /include/buffers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Placeholders of the buffers used in this application. 5 | * 6 | * buffers.h 7 | * 8 | * Created on: Jun 7, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #ifndef BUFFERS_H_ 25 | #define BUFFERS_H_ 26 | 27 | #include "stm32f10x_can.h" 28 | 29 | #define CANBUFLEN 255 30 | #define STREAM_UART 255 31 | #define UARTINSIZE 15 // Count of input strings (+1) for reading USART 32 | #define UARTINLEN 64 33 | // (sizeof("T1111222281122334455667788EA5F\r")+1) and plus first member is length (like in Pascal, heh) 34 | #define UBUFLEN 34 35 | 36 | #define CAN_RW_DIFF(w, r) ((w-r) & CANBUFLEN) 37 | #define UART_RW_DIFF(w, r) ((w-r) & UBUFLEN) 38 | 39 | typedef struct { 40 | uint32_t RIR; 41 | uint32_t RDTR; 42 | uint8_t data[8]; 43 | } can_data_layout_t; 44 | 45 | union CanBuffer { 46 | CAN_FIFOMailBox_TypeDef mailbox; 47 | can_data_layout_t layout; 48 | }; 49 | 50 | 51 | typedef struct { 52 | union CanBuffer rx[CANBUFLEN+1]; 53 | volatile uint32_t read; 54 | volatile uint32_t write; 55 | } can_buf_t; 56 | 57 | typedef struct { 58 | char stream[STREAM_UART+1][UBUFLEN]; 59 | uint32_t read; 60 | volatile uint32_t write; 61 | volatile uint32_t curpos; 62 | } uart_str_buf; 63 | 64 | typedef struct { 65 | char uart_in[UARTINSIZE+1][UARTINLEN]; 66 | volatile uint32_t read; 67 | volatile uint32_t write; 68 | } uart_in_buf_t; 69 | 70 | extern can_buf_t can_rx_buf; 71 | extern uart_in_buf_t uart_in_buf; 72 | extern uart_str_buf uart_out; 73 | 74 | 75 | #endif /* BUFFERS_H_ */ 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lawicel-slcan 2 | 3 | Partial Lawicel/SLCAN implementation at 1 Mb/s CAN speed and 460800 UART baud rate 4 | 5 | ## Required parts 6 | 7 | STM32F103C6 devboard, like Blue Pill or similar. STMF107 can also be used. 8 | FT232RL based USB-USART converter. 9 | SN65HVD230 based CAN bus transceiver (breadboard for simplicity). 10 | 11 | Second FT232 converter can be hooked up to USART3 for debugging (if required). 12 | 13 | ## Implementation details 14 | 15 | The code is optimized to be small and fast. DMA is employed to copy CAN messages to processing buffer and printing out to USART1 for communication with the PC. Lookup tables are employed for converstion to/from ASCII HEX. 16 | 17 | The limitation of 460800 baud rate on UART is due to implementation of using software UART only. I.e. hardware pins CTS/RTS are not employed, they would add reliability. Also shortening wires could help. 18 | 19 | *CAN1 pins are remapped from default ones to PB9 and PB8.* If you don't need remaping, commend out that part in the code. 20 | 21 | JTAG and SWD is fully disabled. If you wish to use that, see first lines in __main__. 22 | 23 | Check [my other pile of STM32 libraries](https://github.com/darauble/STM32-ARM-Libs) for dependencies. 24 | 25 | ## Hooking it up 26 | 27 | Connect UART adapter to PA10 and PA9, flash using native bootloader. 28 | 29 | Connect CAN transceiver to PB9 and PB8. 30 | 31 | ## Setting CAN on Linux 32 | 33 | Linux has __slcan__ daemon and kernel module, which sets up adapter. Then __ip__ can bring it up. So when code is compiled and wires connected, issue the following commands: 34 | 35 | ``` 36 | sudo slcand -S 460800 -t sw /dev/ttyUSB0 can0 37 | sudo ip link set up can0 38 | ``` 39 | 40 | Try __candump can0__ and __cansend__ utilities. 41 | 42 | ## Implemented parts of Lawicel/SLCAN protocol 43 | 44 | Implementation was done according to CAN232 description: http://www.can232.com/docs/can232_v3.pdf 45 | 46 | To this moment I have only implemented partial slcan support: the one I needed quickly. So this boils down to: 47 | - Sending and receiving data and remote request frames, CAN2A and CAN2B ('r', 'R', 't' and 'T' commands) 48 | - Setting on timestamp reporting with 'Z' command 49 | - Reporting version to 'V' command 50 | - Reporting serial number to 'N' command 51 | 52 | So that's basically it. CAN bus is open when device starts up and is hardcoded to 1 Mb/s. Change configuration value of the prescaler if another value is required and better don't mess with TQs. 53 | 54 | -------------------------------------------------------------------------------- /include/slcan_shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Implements ASSCII HEX to binary and back conversion using quick lookup tables. 5 | * 6 | * slcan_config.h 7 | * 8 | * Created on: Jun 8, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | #ifndef PRINTER_PARSER_H_ 24 | #define PRINTER_PARSER_H_ 25 | 26 | #define S_CR '\r' 27 | #define S_NL '\n' 28 | #define S_BELL '\a' 29 | 30 | #define CAN_RETRIES 3 31 | 32 | #define DB_SLCAN_VERSION "V3001\r" 33 | #define DB_SLCAN_VER_LEN 6 34 | 35 | #include "stm32f10x_can.h" 36 | #include "buffers.h" 37 | 38 | /** 39 | * Convert incoming CAN message into Lawicel representation. First byte of the buffer 40 | * contains length of the converted string, like in Pascal. This makes DMA-UART operation 41 | * quicker, as there's no need to count string's length. 42 | * @param pointer to incoming (RX) message 43 | * @param pointer to the buffer where to put message 44 | * @param max lenght of the buffer (should be >=34 bytes) 45 | * @return 0 if ok, error code otherwise 46 | */ 47 | int32_t print_can(union CanBuffer *, char*, int32_t); 48 | 49 | /** 50 | * Checks if there's ongoing UART input parsing. During parsing output buffer should not be filled, 51 | * even if there are incoming CAN messages. 52 | * @return 1 if parsing's ongoing, 0 if there's no parsing activity 53 | */ 54 | int32_t is_parsing(); 55 | 56 | /** 57 | * Function to be called periodically to process buffer of incoming CAN messages and filling 58 | * in the output buffer with appropriate Lawicel representation. 59 | */ 60 | void handle_can_printing(); 61 | 62 | void handle_uart_output(); 63 | 64 | /** 65 | * Function to be called periodically to read input from UART and put it into incomming buffer 66 | * for further processing and sending out CAN messages. 67 | */ 68 | void handle_shell(); 69 | 70 | /** 71 | * Function to be called periodically to check if there is UART buffer filled with messages to be sent. 72 | */ 73 | void handle_can_send(); 74 | 75 | #endif /* PRINTER_PARSER_H_ */ 76 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source main routines implementing Lawicel SLCAN (CAN232) device 3 | * 4 | * main.c 5 | * 6 | * Created on: June 5, 2018 7 | * Author: Darau, blė 8 | * 9 | * Credits: http://www.can232.com/docs/can232_v3.pdf 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | #include "makrosai.h" 28 | #include "systick-utils.h" 29 | 30 | #include "led.h" 31 | #include "usart.h" 32 | #include "can.h" 33 | #include "buffers.h" 34 | #include "slcan_shell.h" 35 | 36 | #ifdef __DEBUG_UART__ 37 | #include "debug_uart.h" 38 | #endif 39 | 40 | const char *hello = "Starting \"Darau, Ble\" implementation of Lawicel SLCAN, v0.0.3\r\n"; 41 | 42 | int main(int argc, char* argv[]) 43 | { 44 | if (argc) argv++; // Just to shut up warning on unused variables 45 | 46 | REMAP_JTAG_FULL_DISABLE; 47 | 48 | LED_PORT_INIT; 49 | LED_ON(LED_RED); 50 | 51 | init_systick_utils(); 52 | #ifdef __DEBUG_UART__ 53 | open_dbg_uart(); 54 | dbg_print("SLCAN debug started on USART3\r\n"); 55 | #endif 56 | 57 | /*********************************************************************************************************** 58 | * Could not get FT232 USB adapter working faster than this baud rate. Might be limitation of UART, as 59 | * CTS and RTS pins are not employed for hardware RS232. 60 | ***********************************************************************************************************/ 61 | init_usart(460800); 62 | 63 | write_usart(hello, strlen(hello)); 64 | 65 | int32_t cs = open_can(); 66 | 67 | #ifdef __DEBUG_UART__ 68 | snprintf(dbg_buf, DBG_BUF_LEN, "CAN: %ld\r\n", cs); 69 | dbg_print_buf(); 70 | #endif 71 | 72 | if (cs != 0) { 73 | // Error, not possible to do anything meaningful, so shine all leds. 74 | LED_ON(LED_RED); 75 | LED_ON(LED_GREEN); 76 | LED_ON(LED_BLUE); 77 | while (1); 78 | } 79 | 80 | while (1) { 81 | handle_red_blink(); 82 | 83 | handle_green_blink(); 84 | 85 | handle_can_printing(); 86 | 87 | handle_uart_output(); 88 | 89 | handle_shell(); 90 | 91 | handle_can_send(); 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /include/stm32f10x_conf.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file Project/STM32F10x_StdPeriph_Template/stm32f10x_conf.h 4 | * @author MCD Application Team 5 | * @version V3.5.0 6 | * @date 08-April-2011 7 | * @brief Library configuration file. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 12 | * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 13 | * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY 14 | * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 15 | * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 16 | * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 17 | * 18 | *

© COPYRIGHT 2011 STMicroelectronics

19 | ****************************************************************************** 20 | */ 21 | 22 | /* Define to prevent recursive inclusion -------------------------------------*/ 23 | #ifndef __STM32F10x_CONF_H 24 | #define __STM32F10x_CONF_H 25 | 26 | /* Includes ------------------------------------------------------------------*/ 27 | /* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */ 28 | #include "stm32f10x_adc.h" 29 | #include "stm32f10x_bkp.h" 30 | #include "stm32f10x_can.h" 31 | #include "stm32f10x_cec.h" 32 | #include "stm32f10x_crc.h" 33 | #include "stm32f10x_dac.h" 34 | #include "stm32f10x_dbgmcu.h" 35 | #include "stm32f10x_dma.h" 36 | #include "stm32f10x_exti.h" 37 | #include "stm32f10x_flash.h" 38 | #include "stm32f10x_fsmc.h" 39 | #include "stm32f10x_gpio.h" 40 | #include "stm32f10x_i2c.h" 41 | #include "stm32f10x_iwdg.h" 42 | #include "stm32f10x_pwr.h" 43 | #include "stm32f10x_rcc.h" 44 | #include "stm32f10x_rtc.h" 45 | #include "stm32f10x_sdio.h" 46 | #include "stm32f10x_spi.h" 47 | #include "stm32f10x_tim.h" 48 | #include "stm32f10x_usart.h" 49 | #include "stm32f10x_wwdg.h" 50 | #include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */ 51 | 52 | /* Exported types ------------------------------------------------------------*/ 53 | /* Exported constants --------------------------------------------------------*/ 54 | /* Uncomment the line below to expanse the "assert_param" macro in the 55 | Standard Peripheral Library drivers code */ 56 | /* #define USE_FULL_ASSERT 1 */ 57 | 58 | /* Exported macro ------------------------------------------------------------*/ 59 | #ifdef USE_FULL_ASSERT 60 | 61 | /** 62 | * @brief The assert_param macro is used for function's parameters check. 63 | * @param expr: If expr is false, it calls assert_failed function which reports 64 | * the name of the source file and the source line number of the call 65 | * that failed. If expr is true, it returns no value. 66 | * @retval None 67 | */ 68 | #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) 69 | /* Exported functions ------------------------------------------------------- */ 70 | void assert_failed(uint8_t* file, uint32_t line); 71 | #else 72 | #define assert_param(expr) ((void)0) 73 | #endif /* USE_FULL_ASSERT */ 74 | 75 | //#define VECT_TAB_SRAM 76 | 77 | #endif /* __STM32F10x_CONF_H */ 78 | 79 | /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/ 80 | -------------------------------------------------------------------------------- /src/usart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device 3 | * 4 | * Implements USART printing via DMA and non-blocking reading. 5 | * 6 | * usart.c 7 | * 8 | * Created on: June 5, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include "stm32f10x.h" 25 | #include "usart.h" 26 | 27 | const uint32_t bauds[] = { 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1000000, 0 }; 28 | const uint16_t brr_u[] = { 0xEA60, 0x7530, 0x3A98, 0x1D4C, 0x0EA6, 0x0753, 0x04E2, 0x0271, 0x0138, 0x009C, 0x004E, 0x0048 }; 29 | 30 | #define USART USART1 31 | #define DMA DMA1 32 | #define DMA_CH DMA1_Channel4 33 | #define DMA_CLK RCC_AHBENR_DMA1EN 34 | #define DMA_IFCR_CLEAR (DMA_ISR_GIF4 | DMA_ISR_TCIF4 | DMA_ISR_HTIF4 | DMA_ISR_TEIF4) 35 | #define DMA_TX_FLAG DMA_ISR_TCIF4 36 | #define DMA_IRQ_H DMA1_Channel4_IRQHandler 37 | #define DMA_IRQ DMA1_Channel4_IRQn 38 | 39 | static volatile int32_t sending = 0; 40 | 41 | void init_usart(uint32_t baud_rate) 42 | { 43 | RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; 44 | RCC->APB2ENR |= RCC_APB2ENR_USART1EN; 45 | RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; 46 | GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10 | GPIO_CRH_MODE10); // Clear configuration 47 | GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10_0; // Alternative Push-pull, 50 MHz; in floating 48 | 49 | // Clear config 50 | USART->CR1 = 0; 51 | USART->CR2 = 0; 52 | USART->CR3 = 0; 53 | USART->CR1 |= USART_CR1_UE | USART_CR1_RE | USART_CR1_TE; 54 | 55 | set_baud_rate(baud_rate); 56 | 57 | RCC->AHBENR |= DMA_CLK; 58 | 59 | // Configure DMA NVIC 60 | NVIC->IP[DMA_IRQ] = 0x00; 61 | NVIC->ISER[DMA_IRQ >> 0x05] = (uint32_t) 0x001 << (DMA_IRQ & (uint8_t) 0x1F); 62 | 63 | // Configure Memory to UART DMA 64 | DMA_CH->CPAR = (uint32_t) &(USART1->DR); 65 | DMA_CH->CCR = 0; 66 | DMA_CH->CCR = (DMA_CCR1_MINC | DMA_CCR1_DIR | DMA_CCR1_TCIE); // Increment memory buffer | Memory to peripheral 67 | 68 | } 69 | 70 | void set_baud_rate(uint32_t baud_rate) 71 | { 72 | int32_t i = 0; 73 | while (bauds[i]) { 74 | if (bauds[i] == baud_rate) { 75 | USART->BRR = brr_u[i]; 76 | break; 77 | } 78 | i++; 79 | } 80 | if (bauds[i] == 0) { 81 | // default to 9600 82 | USART->BRR = brr_u[2]; 83 | } 84 | } 85 | 86 | uint32_t is_sending(void) 87 | { 88 | return sending; 89 | } 90 | 91 | void write_usart(const char *str, int32_t len) 92 | { 93 | while (sending); 94 | 95 | start_tx_usart(str, len); 96 | } 97 | 98 | void start_tx_usart(const char *str, int32_t len) 99 | { 100 | sending = 1; 101 | USART->SR = ~( USART_FLAG_TC | USART_FLAG_RXNE); 102 | 103 | DMA_CH->CMAR = (uint32_t) str; 104 | DMA_CH->CNDTR = len; 105 | 106 | DMA->IFCR |= DMA_IFCR_CLEAR; 107 | USART->CR3 |= USART_CR3_DMAT; 108 | DMA_CH->CCR |= DMA_CCR1_EN; 109 | } 110 | 111 | int read_usart_nonblock(char *c) 112 | { 113 | if (!(USART->SR & USART_SR_RXNE)) { 114 | return 0; // Nothing to read 115 | } else { 116 | *c = USART->DR; 117 | return 1; 118 | } 119 | } 120 | 121 | void DMA_IRQ_H(void) 122 | { 123 | if (((DMA->ISR & DMA_TX_FLAG) > 0)) { 124 | // Wait for USART to finish sending last byte, it still works for some cycles 125 | // after DMA transfer is done. 126 | while ((USART->SR & USART_SR_TC) == 0); 127 | 128 | DMA_CH->CCR &= ~DMA_CCR1_EN; 129 | USART->CR3 &= (uint16_t) ~USART_CR3_DMAT; 130 | DMA->IFCR |= DMA_IFCR_CLEAR; 131 | sending = 0; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/can.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Implements CAN bus initialization and reading via interrupt. 5 | * 6 | * can.c 7 | * 8 | * Created on: Jun 6, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include 25 | 26 | #include "stm32f10x.h" 27 | #include "stm32f10x_can.h" // For CAN_Receive 28 | #include "misc.h" 29 | #include "can.h" 30 | #include "buffers.h" 31 | #include "led.h" 32 | #include "slcan_config.h" 33 | 34 | //#define CAN_MCR_RESET (uint32_t) 0x00010002 35 | #define INAK_TIMEOUT (uint32_t) 0xFFFF; 36 | #define CAN_CFG_FLAGS (CAN_MCR_ABOM) 37 | 38 | #define AIRCR_VECTKEY_MASK ((uint32_t)0x05FA0000) 39 | #define NVIC_PriorityGroup_1 ((uint32_t)0x600) 40 | 41 | #ifndef STM32F10X_CL 42 | #define CAN1_RX_IRQ_CH USB_LP_CAN1_RX0_IRQn 43 | #else 44 | #define CAN1_RX_IRQ_CH CAN1_RX0_IRQn 45 | #endif 46 | 47 | extern char buf[100]; 48 | extern volatile int len; 49 | 50 | static CanRxMsg rx_msg; 51 | 52 | int open_can() 53 | { 54 | // Configure NVIC for CAN 55 | /*SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup_1; 56 | NVIC->IP[CAN1_RX_IRQ_CH] = 0x00; 57 | NVIC->ISER[CAN1_RX_IRQ_CH >> 0x05] = (uint32_t) 0x01 << (CAN1_RX_IRQ_CH & (uint8_t)0x1F);*/ 58 | 59 | NVIC_SetPriority(CAN1_RX_IRQ_CH, 0); 60 | NVIC_EnableIRQ(CAN1_RX_IRQ_CH); 61 | 62 | // Configure IOs for CAN 63 | RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // Enable Alternative IO 64 | RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; // Enable CAN clock 65 | RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable GPIOB pins for CAN1 66 | 67 | GPIOB->CRH &= ~(GPIO_CRH_CNF8 | GPIO_CRH_MODE8 | GPIO_CRH_CNF9 | GPIO_CRH_MODE9); // Reset pin8 and 9 68 | 69 | GPIOB->CRH |= GPIO_CRH_CNF8_1; // CNF b10: input pull up/down, mode 00: input 70 | GPIOB->BSRR |= GPIO_BSRR_BS8; // Pull up 71 | 72 | GPIOB->CRH |= GPIO_CRH_CNF9_1| GPIO_CRH_MODE9; // CNF b10: alternative push-pull, mode 11: 50 MHz output 73 | 74 | //GPIO_PinRemapConfig(GPIO_Remapping_CAN , ENABLE); 75 | AFIO->MAPR &= ~(AFIO_MAPR_CAN_REMAP); 76 | AFIO->MAPR |= AFIO_MAPR_CAN_REMAP_1; // b10, CAN_RX PB8, CAN_TX PB9. 77 | 78 | // Configure CAN peripheral 79 | CAN1->MCR = CAN_MCR_RESET; 80 | CAN1->MCR &= ~CAN_MCR_SLEEP; // Exit from sleep 81 | CAN1->MCR |= CAN_MCR_INRQ; // Request initialisation 82 | 83 | uint32_t timeout = INAK_TIMEOUT; 84 | 85 | while (((CAN1->MSR & CAN_MSR_INAK) == 0) && (--timeout)); 86 | if (timeout == 0) { 87 | CAN1->MCR &= ~(uint32_t)CAN_MCR_INRQ;// Leave initialisation 88 | return -1; // Initialisation failed 89 | } 90 | 91 | CAN1->MCR |= CAN_CFG_FLAGS; 92 | CAN1->BTR = cfg_can_mode 93 | | cfg_can_sjw_quanta 94 | | cfg_can_ts1_quanta 95 | | cfg_can_ts2_quanta 96 | | cfg_can_prescaler; 97 | 98 | CAN1->MCR &= ~(uint32_t)CAN_MCR_INRQ;// Leave initialisation 99 | 100 | timeout = INAK_TIMEOUT; 101 | while (((CAN1->MSR & CAN_MSR_INAK) == 0) && (--timeout)); 102 | if (timeout == 0) { 103 | return -2; // Initialisation finalisation failed 104 | } 105 | //*/ 106 | 107 | // Enable filter 0 to pass through all messages 108 | CAN1->FMR |= CAN_FMR_FINIT; // Enter initialisation 109 | 110 | CAN1->FA1R &= ~(uint32_t)CAN_FA1R_FACT0; // Deactivate filter 111 | CAN1->FS1R |= CAN_FS1R_FSC0; // Scale 32 bit 112 | CAN1->sFilterRegister[0].FR1 = 0x00; // No filter 113 | CAN1->sFilterRegister[0].FR2 = 0x00; 114 | CAN1->FM1R &= ~(uint32_t)CAN_FM1R_FBM0; // Mask mode 115 | CAN1->FFA1R &= (uint32_t)CAN_FFA1R_FFA0; // FIFO0 assignment 116 | CAN1->FA1R |= CAN_FA1R_FACT0; // Activate filter 117 | 118 | CAN1->FMR &= ~CAN_FMR_FINIT; // Exit initialisation 119 | 120 | // Enable CAN interrupt 121 | CAN1->IER |= CAN_IER_FMPIE0; 122 | 123 | 124 | // Configure DMA NVIC 125 | NVIC->IP[CAN_RX_DMA_IRQ] = 0x00; 126 | NVIC->ISER[CAN_RX_DMA_IRQ >> 0x05] = (uint32_t) 0x01 << (CAN_RX_DMA_IRQ & (uint8_t)0x1F); 127 | 128 | return 0; 129 | } 130 | 131 | void close_can() 132 | { 133 | CAN1->IER &= ~(CAN_IER_FMPIE0); 134 | NVIC->ICER[CAN1_RX_IRQ_CH >> 0x05] = (uint32_t) 0x01 << (CAN1_RX_IRQ_CH & (uint8_t)0x1F); 135 | CAN1->MCR = CAN_MCR_RESET; // Reset Master Control Register 136 | RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; // Disable CAN clock 137 | } 138 | 139 | 140 | #ifndef STM32F10X_CL 141 | void USB_LP_CAN1_RX0_IRQHandler(void) 142 | #else 143 | void CAN1_RX0_IRQHandler(void) 144 | #endif 145 | { 146 | blink_green(); 147 | can_rx_buf.rx[can_rx_buf.write].mailbox = CAN1->sFIFOMailBox[0]; // Copy FIFO0 mailbox to buffer 148 | CAN1->RF0R |= CAN_RF0R_RFOM0; // Release FIFO0 149 | can_rx_buf.write = ((can_rx_buf.write+1) & CANBUFLEN); 150 | } 151 | -------------------------------------------------------------------------------- /src/slcan_shell.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The source implementing Lawicel SLCAN (CAN232) device. 3 | * 4 | * Implements ASSCII HEX to binary and back conversion using quick lookup tables. 5 | * 6 | * slcan_shell.c 7 | * 8 | * Created on: Jun 8, 2018 9 | * Author: Darau, blė 10 | * 11 | * This file is a part of personal use libraries and applications. 12 | * 13 | * This program is free software: you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation, either version 3 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This program is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | #include "slcan_shell.h" 25 | #include "usart.h" 26 | #include "systick-utils.h" 27 | #include "led.h" 28 | 29 | #ifdef __DEBUG_UART__ 30 | #include 31 | #include "debug_uart.h" 32 | #endif 33 | 34 | #define SERIAL_NUM (*(uint32_t*) 0x1FFFF7E8) 35 | #define TRANSMIT_DONE 0xFF 36 | #define TRANSMIT_TIMEOUT 100 37 | 38 | //#define CAN_SEND_DEBUG 39 | 40 | #ifdef CAN_SEND_DEBUG 41 | extern char buf[100]; 42 | #endif 43 | 44 | static char bin2hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 45 | static uint32_t hex2bin[] = { 46 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Placeholders for converting ASCII to dec, i.e. gap between digits and letters 48 | 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F 49 | }; 50 | static char msg2type[] = { 't', 'r', 'T', 'R' }; 51 | 52 | // TODO: implement USART baud rate change via U command 53 | //static const uint32_t u2baud[] = { 230400, 115200, 57600, 38400, 19200, 9600, 2400, 460800, 921600, 1000000 }; 54 | 55 | static volatile int32_t parsing = 0; 56 | 57 | static volatile int32_t can_timestamp_on = 0; 58 | 59 | static CanTxMsg tx; 60 | 61 | int32_t print_can(union CanBuffer *rx, char* buf, int32_t len) 62 | { 63 | if (len < 34) { 64 | return -1; 65 | } 66 | 67 | char *cbuf = buf+1; 68 | 69 | // Check if message is remote type (>0 is Remote Request) 70 | int32_t msgtype = ((0x02 & rx->mailbox.RIR) > 0); 71 | 72 | if ((0x04 & rx->mailbox.RIR) > 0) { 73 | msgtype += 2; // Upper case for Extended ID 74 | } 75 | 76 | *cbuf++ = msg2type[msgtype]; 77 | 78 | int32_t i; 79 | uint32_t can_id; 80 | 81 | if ((0x04 & rx->mailbox.RIR) > 0) { 82 | // Extended ID, CAN2B, print 8 Hex characters 83 | can_id = (uint32_t)0x1FFFFFFF & (rx->mailbox.RIR >> 3); 84 | i = 8; 85 | while (i--) { 86 | *cbuf++ = bin2hex[(can_id >> (4*i)) & 0x0F]; 87 | } 88 | } else { 89 | // Standard ID, CAN2A, print 3 Hex characters 90 | can_id = (uint32_t)0x000007FF & (rx->mailbox.RIR >> 21); 91 | i = 3; 92 | while (i--) { 93 | *cbuf++ = bin2hex[(can_id >> (4*i)) & 0x0F]; 94 | } 95 | } 96 | 97 | if ((0x02 & rx->mailbox.RIR) == 0) { 98 | // Data 99 | *cbuf++ = bin2hex[rx->layout.RDTR & 0x0F]; 100 | for (i=0; i<(int32_t)(rx->layout.RDTR & 0x0F); i++) { 101 | *cbuf++ = bin2hex[rx->layout.data[i] >> 4]; 102 | *cbuf++ = bin2hex[rx->layout.data[i] & 0x0F]; 103 | } 104 | } else { 105 | *cbuf++ = '0'; 106 | } 107 | 108 | if (can_timestamp_on) { 109 | uint32_t can_millis = can_timestamp(); 110 | *cbuf++ = bin2hex[(can_millis >> 12) & 0x0F]; 111 | *cbuf++ = bin2hex[(can_millis >> 8) & 0x0F]; 112 | *cbuf++ = bin2hex[(can_millis >> 4) & 0x0F]; 113 | *cbuf++ = bin2hex[(can_millis) & 0x0F]; 114 | } 115 | 116 | *cbuf++ = '\r'; 117 | *cbuf = 0; 118 | 119 | buf[0] = cbuf-&buf[1]; 120 | 121 | return 0; 122 | } 123 | 124 | int32_t is_parsing() 125 | { 126 | return parsing; 127 | } 128 | 129 | 130 | void handle_can_printing() 131 | { 132 | if (!is_parsing() 133 | && ((can_rx_buf.write - can_rx_buf.read) & CANBUFLEN) > 0) 134 | { 135 | print_can(&can_rx_buf.rx[can_rx_buf.read], uart_out.stream[uart_out.write], UBUFLEN); 136 | //write_usart(&buf[1], buf[0]); 137 | //write_usart("\n", 1);//*/ 138 | uart_out.write = (uart_out.write + 1) & STREAM_UART; 139 | can_rx_buf.read = (can_rx_buf.read + 1) & CANBUFLEN;//*/ 140 | } 141 | } 142 | 143 | void handle_uart_output() 144 | { 145 | if (is_sending()) { 146 | return; 147 | } 148 | 149 | if (((uart_out.write - uart_out.read) & STREAM_UART) > 0) { 150 | // Printing queued 151 | start_tx_usart(&uart_out.stream[uart_out.read][1], uart_out.stream[uart_out.read][0]); 152 | uart_out.read = (uart_out.read + 1) & STREAM_UART; 153 | } 154 | } 155 | 156 | static void send_cr() 157 | { 158 | char c = S_CR; 159 | write_usart(&c, 1); 160 | } 161 | 162 | static void send_bell() 163 | { 164 | char c = S_BELL; 165 | write_usart(&c, 1); 166 | } 167 | 168 | static int32_t convert_hex2bin(const char *stream, uint32_t *res, uint32_t len) 169 | { 170 | uint32_t i; 171 | const char *str = stream; 172 | uint32_t ret = 0; 173 | 174 | for (i=0; i= '0' && *str <= 'F') { 176 | ret += hex2bin[(*str) - '0'] << (4*(len-i-1)); 177 | } else { 178 | return -1; 179 | } 180 | str++; 181 | } 182 | 183 | *res = ret; 184 | return 0; 185 | } 186 | 187 | 188 | // TODO: move out USART reading into interrupt, check timeout separately 189 | void handle_shell() 190 | { 191 | static int32_t bufpos = 0; 192 | static int32_t start_millis = 0; 193 | 194 | char *uart_in = uart_in_buf.uart_in[uart_in_buf.write]; 195 | char c; 196 | int read; 197 | 198 | read = read_usart_nonblock(&c); 199 | 200 | if (read) { 201 | if (parsing == 0) { 202 | start_millis = millis(); 203 | } 204 | parsing = 1; 205 | uart_in[bufpos++] = c; 206 | LED_ON(LED_BLUE); 207 | } else { 208 | if (parsing == 1 && (millis() - start_millis > 50)) { 209 | // Timeout in parsing, maybe some error 210 | bufpos = 0; 211 | parsing = 0; 212 | send_bell(); 213 | LED_OFF(LED_BLUE); 214 | } 215 | return; 216 | } 217 | 218 | if (bufpos >= UARTINLEN) { 219 | // Error, should not happen 220 | send_bell(); 221 | bufpos = 0; 222 | return; 223 | #ifdef __DEBUG_UART_ZZ__ 224 | print_usart("Buffer overrun\r\n"); 225 | #endif 226 | } 227 | 228 | if (c == S_CR || c == S_NL) { 229 | // Handle also input "by hand" in terminal 230 | uart_in_buf.write = (uart_in_buf.write + 1) & UARTINSIZE; 231 | 232 | parsing = 0; 233 | bufpos = 0; // Reset buffer in any case when CR/NL received 234 | } else if (millis() - start_millis > 50) { 235 | // Timeout in parsing, maybe some error 236 | bufpos = 0; 237 | parsing = 0; 238 | send_bell(); 239 | LED_OFF(LED_BLUE); 240 | } 241 | } 242 | 243 | static uint8_t last_mbox = TRANSMIT_DONE; 244 | static uint32_t last_send_ts; 245 | void handle_can_send() 246 | { 247 | if (last_mbox != TRANSMIT_DONE) { 248 | // Message was sent previously, check status 249 | if (CAN_TransmitStatus(CAN1, last_mbox) != CAN_TxStatus_Pending) { 250 | // Ok, transmission complete 251 | last_mbox = TRANSMIT_DONE; 252 | send_cr(); // OK 253 | } else if (millis()-last_send_ts >= TRANSMIT_TIMEOUT) { 254 | CAN_CancelTransmit(CAN1, last_mbox); 255 | last_mbox = TRANSMIT_DONE; 256 | send_bell(); // Error 257 | #ifdef __DEBUG_UART__ 258 | dbg_print("Failed to send CAN message\r\n"); 259 | #endif 260 | } else { 261 | // Allow timeout 262 | return; 263 | } 264 | } 265 | 266 | 267 | if (((uart_in_buf.write - uart_in_buf.read) & UARTINSIZE) > 0) { 268 | int32_t res; 269 | int32_t dlc_pos; 270 | uint32_t conv_val; 271 | 272 | char *uart_in = uart_in_buf.uart_in[uart_in_buf.read]; 273 | 274 | #ifdef __DEBUG_UART__ 275 | uart_in[bufpos] = 0; 276 | dbg_print(uart_in); 277 | dbg_print("\n"); 278 | 279 | uint32_t start, end; 280 | start = DWT_CYCCNT; 281 | #endif 282 | 283 | switch(uart_in[0]) { 284 | case 'T': 285 | case 't': 286 | case 'R': 287 | case 'r': 288 | // Parse and transmit message 289 | if (uart_in[0] < 'r') { 290 | // Extended ID 291 | tx.IDE = CAN_Id_Extended; 292 | res = convert_hex2bin(&uart_in[1], &tx.ExtId, 8); 293 | dlc_pos = 9; 294 | } else { 295 | tx.IDE = CAN_Id_Standard; 296 | res = convert_hex2bin(&uart_in[1], &tx.StdId, 3); 297 | dlc_pos = 4; 298 | } 299 | if (res == 0) { 300 | if (uart_in[0] == 't' || uart_in[0] == 'T') { 301 | tx.RTR = CAN_RTR_Data; 302 | res = convert_hex2bin(&uart_in[dlc_pos], &conv_val, 1); 303 | if (res == 0 && conv_val <= 8) { 304 | tx.DLC = (uint8_t) (conv_val & 0xFF); 305 | for (int32_t i = 0; i < tx.DLC; i++) { 306 | res = convert_hex2bin(&uart_in[(dlc_pos + 1)+(i*2)], &conv_val, 2); 307 | if (res == 0) { 308 | tx.Data[i] = (uint8_t) (conv_val & 0xFF); 309 | } else { 310 | break; 311 | } 312 | } 313 | if (res != 0) { 314 | send_bell(); 315 | break; 316 | } 317 | } else { 318 | send_bell(); 319 | break; 320 | } 321 | } else { 322 | tx.RTR = CAN_RTR_Remote; 323 | } 324 | /*********** DEBUG *************/ 325 | #ifdef __DEBUG_UART_ZZ__ 326 | print_usart("\r\n"); 327 | snprintf(dbg_buf, DBG_BUF_LEN, "CAN:\r\n"); 328 | dbg_print_buf(); 329 | snprintf(dbg_buf, DBG_BUF_LEN, " ExtId: %08X\r\n", tx.ExtId); 330 | dbg_print_buf(); 331 | snprintf(dbg_buf, DBG_BUF_LEN, " StdId: %08X\r\n", tx.StdId); 332 | dbg_print_buf(); 333 | snprintf(dbg_buf, DBG_BUF_LEN, " RTR: %02X\r\n", tx.RTR); 334 | dbg_print_buf(); 335 | snprintf(dbg_buf, DBG_BUF_LEN, " DLC: %02X\r\n", tx.DLC); 336 | dbg_print_buf(); 337 | snprintf(dbg_buf, DBG_BUF_LEN, " Data: %02X %02X %02X %02X %02X %02X %02X %02X\r\n\r\n", 338 | tx.Data[0], tx.Data[1], tx.Data[2], tx.Data[3], tx.Data[4], tx.Data[5], tx.Data[6], tx.Data[7]); 339 | dbg_print_buf(); 340 | #endif 341 | /*******************************/ 342 | last_mbox = CAN_Transmit(CAN1, &tx); 343 | last_send_ts = millis(); 344 | } else { 345 | send_bell(); 346 | } 347 | break; 348 | case 'N': 349 | // Report serial number (taken from STM32F103 ID register 350 | if (uart_in[1] == S_CR || uart_in[1] == S_NL) { 351 | uart_out.stream[uart_out.write][0] = 6; 352 | uart_out.stream[uart_out.write][1] = 'N'; 353 | uart_out.stream[uart_out.write][2] = bin2hex[(SERIAL_NUM >> 12) & 0x0F]; 354 | uart_out.stream[uart_out.write][3] = bin2hex[(SERIAL_NUM >> 8) & 0x0F]; 355 | uart_out.stream[uart_out.write][4] = bin2hex[(SERIAL_NUM >> 4) & 0x0F]; 356 | uart_out.stream[uart_out.write][5] = bin2hex[(SERIAL_NUM) & 0x0F]; 357 | uart_out.stream[uart_out.write][6] = S_CR; 358 | uart_out.write = (uart_out.write + 1) & STREAM_UART; 359 | } else { 360 | // That's some gibberish, send error 361 | send_bell(); 362 | } 363 | break; 364 | case 'U': 365 | // Set UART baud rate 366 | break; 367 | case 'V': 368 | if (uart_in[1] == S_CR || uart_in[1] == S_NL) { 369 | write_usart(DB_SLCAN_VERSION, DB_SLCAN_VER_LEN); 370 | } else { 371 | // That's some gibberish, send error 372 | send_bell(); 373 | } 374 | break; 375 | case 'Z': 376 | // Turn the timestamp on/off 377 | if (uart_in[2] == S_CR || uart_in[2] == S_NL) { 378 | if (uart_in[1] == '1') { 379 | can_timestamp_on = 1; 380 | send_cr(); 381 | } else if (uart_in[1] == '0') { 382 | can_timestamp_on = 0; 383 | send_cr(); 384 | } else { 385 | // Something's not supported 386 | send_bell(); 387 | } 388 | 389 | } else { 390 | send_bell(); 391 | } 392 | break; 393 | default: 394 | // Something's not supported (yet?) 395 | send_bell(); 396 | break; 397 | } 398 | uart_in_buf.read = (uart_in_buf.read + 1) & UARTINSIZE; // Next buffer in the row 399 | parsing = 0; // Also reset parsing flag so output could be enabled 400 | LED_OFF(LED_BLUE); 401 | #ifdef __DEBUG_UART__ 402 | end = DWT_CYCCNT; 403 | snprintf(dbg_buf, DBG_BUF_LEN, "Parsing cycles: %lu, %lu, %lu\r\n", start, end, end - start); 404 | dbg_print_buf(); 405 | #endif 406 | // End of processing 407 | 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /ldscripts/sections.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Default linker script for Cortex-M (it includes specifics for STM32F[34]xx). 3 | * 4 | * To make use of the multi-region initialisations, define 5 | * OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file. 6 | */ 7 | 8 | /* 9 | * The '__stack' definition is required by crt0, do not remove it. 10 | */ 11 | __stack = ORIGIN(RAM) + LENGTH(RAM); 12 | 13 | _estack = __stack; /* STM specific definition */ 14 | 15 | /* 16 | * Default stack sizes. 17 | * These are used by the startup in order to allocate stacks 18 | * for the different modes. 19 | */ 20 | 21 | __Main_Stack_Size = 1024 ; 22 | 23 | PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ; 24 | 25 | __Main_Stack_Limit = __stack - __Main_Stack_Size ; 26 | 27 | /* "PROVIDE" allows to easily override these values from an 28 | * object file or the command line. */ 29 | PROVIDE ( _Main_Stack_Limit = __Main_Stack_Limit ) ; 30 | 31 | /* 32 | * There will be a link error if there is not this amount of 33 | * RAM free at the end. 34 | */ 35 | _Minimum_Stack_Size = 256 ; 36 | 37 | /* 38 | * Default heap definitions. 39 | * The heap start immediately after the last statically allocated 40 | * .sbss/.noinit section, and extends up to the main stack limit. 41 | */ 42 | PROVIDE ( _Heap_Begin = _end_noinit ) ; 43 | PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ; 44 | 45 | /* 46 | * The entry point is informative, for debuggers and simulators, 47 | * since the Cortex-M vector points to it anyway. 48 | */ 49 | ENTRY(_start) 50 | 51 | 52 | /* Sections Definitions */ 53 | 54 | SECTIONS 55 | { 56 | /* 57 | * For Cortex-M devices, the beginning of the startup code is stored in 58 | * the .isr_vector section, which goes to FLASH. 59 | */ 60 | .isr_vector : ALIGN(4) 61 | { 62 | FILL(0xFF) 63 | 64 | __vectors_start = ABSOLUTE(.) ; 65 | __vectors_start__ = ABSOLUTE(.) ; /* STM specific definition */ 66 | KEEP(*(.isr_vector)) /* Interrupt vectors */ 67 | 68 | KEEP(*(.cfmconfig)) /* Freescale configuration words */ 69 | 70 | /* 71 | * This section is here for convenience, to store the 72 | * startup code at the beginning of the flash area, hoping that 73 | * this will increase the readability of the listing. 74 | */ 75 | *(.after_vectors .after_vectors.*) /* Startup code and ISR */ 76 | 77 | } >FLASH 78 | 79 | .inits : ALIGN(4) 80 | { 81 | /* 82 | * Memory regions initialisation arrays. 83 | * 84 | * Thee are two kinds of arrays for each RAM region, one for 85 | * data and one for bss. Each is iterrated at startup and the 86 | * region initialisation is performed. 87 | * 88 | * The data array includes: 89 | * - from (LOADADDR()) 90 | * - region_begin (ADDR()) 91 | * - region_end (ADDR()+SIZEOF()) 92 | * 93 | * The bss array includes: 94 | * - region_begin (ADDR()) 95 | * - region_end (ADDR()+SIZEOF()) 96 | * 97 | * WARNING: It is mandatory that the regions are word aligned, 98 | * since the initialisation code works only on words. 99 | */ 100 | 101 | __data_regions_array_start = .; 102 | 103 | LONG(LOADADDR(.data)); 104 | LONG(ADDR(.data)); 105 | LONG(ADDR(.data)+SIZEOF(.data)); 106 | 107 | LONG(LOADADDR(.data_CCMRAM)); 108 | LONG(ADDR(.data_CCMRAM)); 109 | LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM)); 110 | 111 | __data_regions_array_end = .; 112 | 113 | __bss_regions_array_start = .; 114 | 115 | LONG(ADDR(.bss)); 116 | LONG(ADDR(.bss)+SIZEOF(.bss)); 117 | 118 | LONG(ADDR(.bss_CCMRAM)); 119 | LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM)); 120 | 121 | __bss_regions_array_end = .; 122 | 123 | /* End of memory regions initialisation arrays. */ 124 | 125 | /* 126 | * These are the old initialisation sections, intended to contain 127 | * naked code, with the prologue/epilogue added by crti.o/crtn.o 128 | * when linking with startup files. The standalone startup code 129 | * currently does not run these, better use the init arrays below. 130 | */ 131 | KEEP(*(.init)) 132 | KEEP(*(.fini)) 133 | 134 | . = ALIGN(4); 135 | 136 | /* 137 | * The preinit code, i.e. an array of pointers to initialisation 138 | * functions to be performed before constructors. 139 | */ 140 | PROVIDE_HIDDEN (__preinit_array_start = .); 141 | 142 | /* 143 | * Used to run the SystemInit() before anything else. 144 | */ 145 | KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*)) 146 | 147 | /* 148 | * Used for other platform inits. 149 | */ 150 | KEEP(*(.preinit_array_platform .preinit_array_platform.*)) 151 | 152 | /* 153 | * The application inits. If you need to enforce some order in 154 | * execution, create new sections, as before. 155 | */ 156 | KEEP(*(.preinit_array .preinit_array.*)) 157 | 158 | PROVIDE_HIDDEN (__preinit_array_end = .); 159 | 160 | . = ALIGN(4); 161 | 162 | /* 163 | * The init code, i.e. an array of pointers to static constructors. 164 | */ 165 | PROVIDE_HIDDEN (__init_array_start = .); 166 | KEEP(*(SORT(.init_array.*))) 167 | KEEP(*(.init_array)) 168 | PROVIDE_HIDDEN (__init_array_end = .); 169 | 170 | . = ALIGN(4); 171 | 172 | /* 173 | * The fini code, i.e. an array of pointers to static destructors. 174 | */ 175 | PROVIDE_HIDDEN (__fini_array_start = .); 176 | KEEP(*(SORT(.fini_array.*))) 177 | KEEP(*(.fini_array)) 178 | PROVIDE_HIDDEN (__fini_array_end = .); 179 | 180 | } >FLASH 181 | 182 | /* 183 | * For some STRx devices, the beginning of the startup code 184 | * is stored in the .flashtext section, which goes to FLASH. 185 | */ 186 | .flashtext : ALIGN(4) 187 | { 188 | *(.flashtext .flashtext.*) /* Startup code */ 189 | } >FLASH 190 | 191 | 192 | /* 193 | * The program code is stored in the .text section, 194 | * which goes to FLASH. 195 | */ 196 | .text : ALIGN(4) 197 | { 198 | *(.text .text.*) /* all remaining code */ 199 | 200 | /* read-only data (constants) */ 201 | *(.rodata .rodata.* .constdata .constdata.*) 202 | 203 | *(vtable) /* C++ virtual tables */ 204 | 205 | KEEP(*(.eh_frame*)) 206 | 207 | /* 208 | * Stub sections generated by the linker, to glue together 209 | * ARM and Thumb code. .glue_7 is used for ARM code calling 210 | * Thumb code, and .glue_7t is used for Thumb code calling 211 | * ARM code. Apparently always generated by the linker, for some 212 | * architectures, so better leave them here. 213 | */ 214 | *(.glue_7) 215 | *(.glue_7t) 216 | 217 | } >FLASH 218 | 219 | /* ARM magic sections */ 220 | .ARM.extab : ALIGN(4) 221 | { 222 | *(.ARM.extab* .gnu.linkonce.armextab.*) 223 | } > FLASH 224 | 225 | . = ALIGN(4); 226 | __exidx_start = .; 227 | .ARM.exidx : ALIGN(4) 228 | { 229 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 230 | } > FLASH 231 | __exidx_end = .; 232 | 233 | . = ALIGN(4); 234 | _etext = .; 235 | __etext = .; 236 | 237 | /* MEMORY_ARRAY */ 238 | /* 239 | .ROarraySection : 240 | { 241 | *(.ROarraySection .ROarraySection.*) 242 | } >MEMORY_ARRAY 243 | */ 244 | 245 | /* 246 | * The secondary initialised data section. 247 | */ 248 | .data_CCMRAM : ALIGN(4) 249 | { 250 | FILL(0xFF) 251 | *(.data.CCMRAM .data.CCMRAM.*) 252 | . = ALIGN(4) ; 253 | } > CCMRAM AT>FLASH 254 | 255 | /* 256 | * This address is used by the startup code to 257 | * initialise the .data section. 258 | */ 259 | _sidata = LOADADDR(.data); 260 | 261 | /* 262 | * The initialised data section. 263 | * 264 | * The program executes knowing that the data is in the RAM 265 | * but the loader puts the initial values in the FLASH (inidata). 266 | * It is one task of the startup to copy the initial values from 267 | * FLASH to RAM. 268 | */ 269 | .data : ALIGN(4) 270 | { 271 | FILL(0xFF) 272 | /* This is used by the startup code to initialise the .data section */ 273 | _sdata = . ; /* STM specific definition */ 274 | __data_start__ = . ; 275 | *(.data_begin .data_begin.*) 276 | 277 | *(.data .data.*) 278 | 279 | *(.data_end .data_end.*) 280 | . = ALIGN(4); 281 | 282 | /* This is used by the startup code to initialise the .data section */ 283 | _edata = . ; /* STM specific definition */ 284 | __data_end__ = . ; 285 | 286 | } >RAM AT>FLASH 287 | 288 | /* 289 | * The uninitialised data sections. NOLOAD is used to avoid 290 | * the "section `.bss' type changed to PROGBITS" warning 291 | */ 292 | 293 | /* The secondary uninitialised data section. */ 294 | .bss_CCMRAM (NOLOAD) : ALIGN(4) 295 | { 296 | *(.bss.CCMRAM .bss.CCMRAM.*) 297 | } > CCMRAM 298 | 299 | /* The primary uninitialised data section. */ 300 | .bss (NOLOAD) : ALIGN(4) 301 | { 302 | __bss_start__ = .; /* standard newlib definition */ 303 | _sbss = .; /* STM specific definition */ 304 | *(.bss_begin .bss_begin.*) 305 | 306 | *(.bss .bss.*) 307 | *(COMMON) 308 | 309 | *(.bss_end .bss_end.*) 310 | . = ALIGN(4); 311 | __bss_end__ = .; /* standard newlib definition */ 312 | _ebss = . ; /* STM specific definition */ 313 | } >RAM 314 | 315 | .noinit_CCMRAM (NOLOAD) : ALIGN(4) 316 | { 317 | *(.noinit.CCMRAM .noinit.CCMRAM.*) 318 | } > CCMRAM 319 | 320 | .noinit (NOLOAD) : ALIGN(4) 321 | { 322 | _noinit = .; 323 | 324 | *(.noinit .noinit.*) 325 | 326 | . = ALIGN(4) ; 327 | _end_noinit = .; 328 | } > RAM 329 | 330 | /* Mandatory to be word aligned, _sbrk assumes this */ 331 | PROVIDE ( end = _end_noinit ); /* was _ebss */ 332 | PROVIDE ( _end = _end_noinit ); 333 | PROVIDE ( __end = _end_noinit ); 334 | PROVIDE ( __end__ = _end_noinit ); 335 | 336 | /* 337 | * Used for validation only, do not allocate anything here! 338 | * 339 | * This is just to check that there is enough RAM left for the Main 340 | * stack. It should generate an error if it's full. 341 | */ 342 | ._check_stack : ALIGN(4) 343 | { 344 | . = . + _Minimum_Stack_Size ; 345 | } >RAM 346 | 347 | /* 348 | * The FLASH Bank1. 349 | * The C or assembly source must explicitly place the code 350 | * or data there using the "section" attribute. 351 | */ 352 | .b1text : ALIGN(4) 353 | { 354 | *(.b1text) /* remaining code */ 355 | *(.b1rodata) /* read-only data (constants) */ 356 | *(.b1rodata.*) 357 | } >FLASHB1 358 | 359 | /* 360 | * The EXTMEM. 361 | * The C or assembly source must explicitly place the code or data there 362 | * using the "section" attribute. 363 | */ 364 | 365 | /* EXTMEM Bank0 */ 366 | .eb0text : ALIGN(4) 367 | { 368 | *(.eb0text) /* remaining code */ 369 | *(.eb0rodata) /* read-only data (constants) */ 370 | *(.eb0rodata.*) 371 | } >EXTMEMB0 372 | 373 | /* EXTMEM Bank1 */ 374 | .eb1text : ALIGN(4) 375 | { 376 | *(.eb1text) /* remaining code */ 377 | *(.eb1rodata) /* read-only data (constants) */ 378 | *(.eb1rodata.*) 379 | } >EXTMEMB1 380 | 381 | /* EXTMEM Bank2 */ 382 | .eb2text : ALIGN(4) 383 | { 384 | *(.eb2text) /* remaining code */ 385 | *(.eb2rodata) /* read-only data (constants) */ 386 | *(.eb2rodata.*) 387 | } >EXTMEMB2 388 | 389 | /* EXTMEM Bank0 */ 390 | .eb3text : ALIGN(4) 391 | { 392 | *(.eb3text) /* remaining code */ 393 | *(.eb3rodata) /* read-only data (constants) */ 394 | *(.eb3rodata.*) 395 | } >EXTMEMB3 396 | 397 | 398 | /* After that there are only debugging sections. */ 399 | 400 | /* This can remove the debugging information from the standard libraries */ 401 | /* 402 | DISCARD : 403 | { 404 | libc.a ( * ) 405 | libm.a ( * ) 406 | libgcc.a ( * ) 407 | } 408 | */ 409 | 410 | /* Stabs debugging sections. */ 411 | .stab 0 : { *(.stab) } 412 | .stabstr 0 : { *(.stabstr) } 413 | .stab.excl 0 : { *(.stab.excl) } 414 | .stab.exclstr 0 : { *(.stab.exclstr) } 415 | .stab.index 0 : { *(.stab.index) } 416 | .stab.indexstr 0 : { *(.stab.indexstr) } 417 | .comment 0 : { *(.comment) } 418 | /* 419 | * DWARF debug sections. 420 | * Symbols in the DWARF debugging sections are relative to the beginning 421 | * of the section so we begin them at 0. 422 | */ 423 | /* DWARF 1 */ 424 | .debug 0 : { *(.debug) } 425 | .line 0 : { *(.line) } 426 | /* GNU DWARF 1 extensions */ 427 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 428 | .debug_sfnames 0 : { *(.debug_sfnames) } 429 | /* DWARF 1.1 and DWARF 2 */ 430 | .debug_aranges 0 : { *(.debug_aranges) } 431 | .debug_pubnames 0 : { *(.debug_pubnames) } 432 | /* DWARF 2 */ 433 | .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } 434 | .debug_abbrev 0 : { *(.debug_abbrev) } 435 | .debug_line 0 : { *(.debug_line) } 436 | .debug_frame 0 : { *(.debug_frame) } 437 | .debug_str 0 : { *(.debug_str) } 438 | .debug_loc 0 : { *(.debug_loc) } 439 | .debug_macinfo 0 : { *(.debug_macinfo) } 440 | /* SGI/MIPS DWARF 2 extensions */ 441 | .debug_weaknames 0 : { *(.debug_weaknames) } 442 | .debug_funcnames 0 : { *(.debug_funcnames) } 443 | .debug_typenames 0 : { *(.debug_typenames) } 444 | .debug_varnames 0 : { *(.debug_varnames) } 445 | } 446 | --------------------------------------------------------------------------------