xref: /btstack/port/stm32-f4discovery-cc256x/port/port.c (revision bbc6d413293156c7b1ae7a92291217ae2c1aa7fa)
1 #define BTSTACK_FILE__ "port.c"
2 
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <signal.h>
6 
7 // include STM32 first to avoid warning about redefinition of UNUSED
8 #include "stm32f4xx_hal.h"
9 #include "main.h"
10 
11 #include "port.h"
12 #include "btstack.h"
13 #include "btstack_debug.h"
14 #include "btstack_audio.h"
15 #include "btstack_chipset_cc256x.h"
16 #include "btstack_run_loop_embedded.h"
17 #include "btstack_tlv.h"
18 #include "btstack_tlv_flash_bank.h"
19 #include "hci_transport.h"
20 #include "hci_transport_h4.h"
21 #include "ble/le_device_db_tlv.h"
22 #include "classic/btstack_link_key_db_static.h"
23 #include "classic/btstack_link_key_db_tlv.h"
24 #include "hal_flash_bank_stm32.h"
25 
26 #ifdef ENABLE_SEGGER_RTT
27 #include "SEGGER_RTT.h"
28 #include "hci_dump_segger_rtt_stdout.h"
29 #else
30 #include "hci_dump_embedded_stdout.h"
31 #endif
32 
33 //
34 extern UART_HandleTypeDef huart2;
35 extern UART_HandleTypeDef huart3;
36 
37 //
38 static btstack_packet_callback_registration_t hci_event_callback_registration;
39 
40 static const hci_transport_config_uart_t config = {
41     HCI_TRANSPORT_CONFIG_UART,
42     115200,
43     4000000,
44     1,
45     NULL,
46     BTSTACK_UART_PARITY_OFF
47 };
48 
49 // hal_time_ms.h
50 #include "hal_time_ms.h"
hal_time_ms(void)51 uint32_t hal_time_ms(void){
52     return HAL_GetTick();
53 }
54 
55 // hal_cpu.h implementation
56 #include "hal_cpu.h"
57 
hal_cpu_disable_irqs(void)58 void hal_cpu_disable_irqs(void){
59     __disable_irq();
60 }
61 
hal_cpu_enable_irqs(void)62 void hal_cpu_enable_irqs(void){
63     __enable_irq();
64 }
65 
hal_cpu_enable_irqs_and_sleep(void)66 void hal_cpu_enable_irqs_and_sleep(void){
67     __enable_irq();
68     __asm__("wfe"); // go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag
69 }
70 
71 // hal_stdin.h
72 #include "hal_stdin.h"
73 static uint8_t stdin_buffer[1];
74 static void (*stdin_handler)(char c);
hal_stdin_setup(void (* handler)(char c))75 void hal_stdin_setup(void (*handler)(char c)){
76     stdin_handler = handler;
77     // start receiving
78     HAL_UART_Receive_IT(&huart2, &stdin_buffer[0], 1);
79 }
80 
stdin_rx_complete(void)81 static void stdin_rx_complete(void){
82     if (stdin_handler){
83         (*stdin_handler)(stdin_buffer[0]);
84     }
85     HAL_UART_Receive_IT(&huart2, &stdin_buffer[0], 1);
86 }
87 
88 // hal_uart_dma.h
89 
90 // hal_uart_dma.c implementation
91 #include "hal_uart_dma.h"
92 
93 static void dummy_handler(void);
94 
95 // handlers
96 static void (*rx_done_handler)(void) = &dummy_handler;
97 static void (*tx_done_handler)(void) = &dummy_handler;
98 static void (*cts_irq_handler)(void) = &dummy_handler;
99 
100 static int hal_uart_needed_during_sleep;
101 
dummy_handler(void)102 static void dummy_handler(void){}
103 
hal_uart_dma_set_sleep(uint8_t sleep)104 void hal_uart_dma_set_sleep(uint8_t sleep){
105 
106     // RTS is on PD12 - manually set it during sleep
107     GPIO_InitTypeDef RTS_InitStruct;
108     RTS_InitStruct.Pin = GPIO_PIN_12;
109     RTS_InitStruct.Pull = GPIO_NOPULL;
110     RTS_InitStruct.Alternate = GPIO_AF7_USART3;
111     if (sleep){
112         HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
113         RTS_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
114         RTS_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
115     } else {
116         RTS_InitStruct.Mode = GPIO_MODE_AF_PP;
117         RTS_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
118     }
119 
120     HAL_GPIO_Init(GPIOD, &RTS_InitStruct);
121 
122 //  if (sleep){
123 //      HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
124 //  }
125     hal_uart_needed_during_sleep = !sleep;
126 }
127 
128 // reset Bluetooth using n_shutdown
bluetooth_power_cycle(void)129 static void bluetooth_power_cycle(void){
130     printf("Bluetooth power cycle\n");
131     HAL_GPIO_WritePin( CC_nSHUTD_GPIO_Port, CC_nSHUTD_Pin, GPIO_PIN_RESET );
132     HAL_Delay( 250 );
133     HAL_GPIO_WritePin( CC_nSHUTD_GPIO_Port, CC_nSHUTD_Pin, GPIO_PIN_SET );
134     HAL_Delay( 500 );
135 }
136 
HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart)137 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
138     if (huart == &huart3){
139         (*tx_done_handler)();
140     }
141 }
142 
HAL_UART_RxCpltCallback(UART_HandleTypeDef * huart)143 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
144     if (huart == &huart3){
145         (*rx_done_handler)();
146     }
147     if (huart == &huart2){
148         stdin_rx_complete();
149     }
150 }
151 
hal_uart_dma_init(void)152 void hal_uart_dma_init(void){
153     bluetooth_power_cycle();
154 }
hal_uart_dma_set_block_received(void (* the_block_handler)(void))155 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
156     rx_done_handler = the_block_handler;
157 }
158 
hal_uart_dma_set_block_sent(void (* the_block_handler)(void))159 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
160     tx_done_handler = the_block_handler;
161 }
162 
EXTI15_10_IRQHandler(void)163 void EXTI15_10_IRQHandler(void){
164     __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_11);
165     if (cts_irq_handler){
166         (*cts_irq_handler)();
167     }
168 }
169 
hal_uart_dma_set_csr_irq_handler(void (* the_irq_handler)(void))170 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){
171 
172     GPIO_InitTypeDef CTS_InitStruct = {
173         .Pin       = GPIO_PIN_11,
174         .Mode      = GPIO_MODE_AF_PP,
175         .Pull      = GPIO_PULLUP,
176         .Speed     = GPIO_SPEED_FREQ_VERY_HIGH,
177         .Alternate = GPIO_AF7_USART3,
178     };
179 
180     if( the_irq_handler )  {
181         /* Configure the EXTI11 interrupt (USART3_CTS is on PD11) */
182         HAL_NVIC_EnableIRQ( EXTI15_10_IRQn );
183         CTS_InitStruct.Mode = GPIO_MODE_IT_RISING;
184         CTS_InitStruct.Pull = GPIO_NOPULL;
185         HAL_GPIO_Init( GPIOD, &CTS_InitStruct );
186         log_info("enabled CTS irq");
187     }
188     else  {
189         CTS_InitStruct.Mode = GPIO_MODE_AF_PP;
190         CTS_InitStruct.Pull = GPIO_PULLUP;
191         HAL_GPIO_Init( GPIOD, &CTS_InitStruct );
192         HAL_NVIC_DisableIRQ( EXTI15_10_IRQn );
193         log_info("disabled CTS irq");
194     }
195     cts_irq_handler = the_irq_handler;
196 }
197 
hal_uart_dma_set_baud(uint32_t baud)198 int  hal_uart_dma_set_baud(uint32_t baud){
199     huart3.Init.BaudRate = baud;
200     HAL_UART_Init(&huart3);
201     return 0;
202 }
203 
hal_uart_dma_send_block(const uint8_t * data,uint16_t size)204 void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){
205     HAL_UART_Transmit_DMA( &huart3, (uint8_t *) data, size);
206 }
207 
hal_uart_dma_receive_block(uint8_t * data,uint16_t size)208 void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){
209     HAL_UART_Receive_DMA( &huart3, data, size );
210 }
211 
212 #ifndef ENABLE_SEGGER_RTT
213 
214 /**
215  * Use USART_CONSOLE as a console.
216  * This is a syscall for newlib
217  * @param file
218  * @param ptr
219  * @param len
220  * @return
221  */
222 
223 ssize_t _write(int file, const void *buf, size_t len);
_write(int file,const void * buf,size_t len)224 ssize_t _write(int file, const void *buf, size_t len){
225 #if 1
226     uint8_t cr = '\r';
227     int i;
228     uint8_t *ptr = buf;
229     if (file == STDOUT_FILENO || file == STDERR_FILENO) {
230         for (i = 0; i < len; i++) {
231             if (ptr[i] == '\n') {
232                 HAL_UART_Transmit( &huart2, &cr, 1, HAL_MAX_DELAY );
233             }
234             HAL_UART_Transmit( &huart2, &ptr[i], 1, HAL_MAX_DELAY );
235         }
236         return i;
237     }
238     errno = EIO;
239     return -1;
240 #else
241     return len;
242 #endif
243 }
244 #endif
245 
_read(int fd,void * buf,size_t count)246 ssize_t _read(int fd, void * buf, size_t count){
247     UNUSED(fd);
248     UNUSED(buf);
249     UNUSED(count);
250     return -1;
251 }
252 
_close(int file)253 int _close(int file){
254     UNUSED(file);
255     return -1;
256 }
257 
_isatty(int file)258 int _isatty(int file){
259     UNUSED(file);
260     return -1;
261 }
262 
_lseek(int file)263 int _lseek(int file){
264     UNUSED(file);
265     return -1;
266 }
267 
_fstat(int file)268 int _fstat(int file){
269     UNUSED(file);
270     return -1;
271 }
272 
_kill(pid_t pid,int sig)273 int _kill (pid_t pid, int sig) {
274     UNUSED(pid);
275     UNUSED(sig);
276     return -1;
277 }
278 
_getpid(void)279 pid_t _getpid (void) {
280     return 0;
281 }
282 
283 // main.c
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)284 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
285     UNUSED(size);
286     UNUSED(channel);
287     bd_addr_t local_addr;
288     if (packet_type != HCI_EVENT_PACKET) return;
289     switch(hci_event_packet_get_type(packet)){
290         case BTSTACK_EVENT_STATE:
291             if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
292             gap_local_bd_addr(local_addr);
293             printf("BTstack up and running on %s.\n", bd_addr_to_str(local_addr));
294             break;
295         case HCI_EVENT_COMMAND_COMPLETE:
296             if (hci_event_command_complete_get_command_opcode(packet) == HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION){
297                 uint16_t manufacturer   = little_endian_read_16(packet, 10);
298                 uint16_t lmp_subversion = little_endian_read_16(packet, 12);
299                 // assert manufacturer is TI
300                 if (manufacturer != BLUETOOTH_COMPANY_ID_TEXAS_INSTRUMENTS_INC){
301                     printf("ERROR: Expected Bluetooth Chipset from TI but got manufacturer 0x%04x\n", manufacturer);
302                     break;
303                 }
304                 // assert correct init script is used based on expected lmp_subversion
305                 if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()){
306                     printf("Error: LMP Subversion does not match initscript! ");
307                     printf("Your initscripts is for %s chipset\n", btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer");
308                     printf("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file\n");
309                     break;
310                 }
311             }
312             break;
313         default:
314             break;
315     }
316 }
317 
318 
319 static btstack_tlv_flash_bank_t btstack_tlv_flash_bank_context;
320 static hal_flash_bank_stm32_t   hal_flash_bank_context;
321 
322 #define HAL_FLASH_BANK_SIZE (128 * 1024)
323 #define HAL_FLASH_BANK_0_ADDR 0x080C0000
324 #define HAL_FLASH_BANK_1_ADDR 0x080E0000
325 #define HAL_FLASH_BANK_0_SECTOR FLASH_SECTOR_10
326 #define HAL_FLASH_BANK_1_SECTOR FLASH_SECTOR_11
327 
328 //
329 int btstack_main(int argc, char ** argv);
port_main(void)330 void port_main(void){
331 
332     // start with BTstack init - especially configure HCI Transport
333     btstack_memory_init();
334     btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
335 
336     // uncomment to enable packet logger
337 #ifdef ENABLE_SEGGER_RTT
338     // hci_dump_init(hci_dump_segger_rtt_stdout_get_instance());
339 #else
340     // hci_dump_init(hci_dump_embedded_stdout_get_instance());
341 #endif
342 
343     // init HCI
344     hci_init(hci_transport_h4_instance(btstack_uart_block_embedded_instance()), (void*) &config);
345     hci_set_chipset(btstack_chipset_cc256x_instance());
346 
347     // setup TLV Flash Sector implementation
348     const hal_flash_bank_t * hal_flash_bank_impl = hal_flash_bank_stm32_init_instance(
349             &hal_flash_bank_context,
350             HAL_FLASH_BANK_SIZE,
351             HAL_FLASH_BANK_0_SECTOR,
352             HAL_FLASH_BANK_1_SECTOR,
353             HAL_FLASH_BANK_0_ADDR,
354             HAL_FLASH_BANK_1_ADDR);
355     const btstack_tlv_t * btstack_tlv_impl = btstack_tlv_flash_bank_init_instance(
356             &btstack_tlv_flash_bank_context,
357             hal_flash_bank_impl,
358             &hal_flash_bank_context);
359 
360     // setup global tlv
361     btstack_tlv_set_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
362 
363     // setup Link Key DB using TLV
364     const btstack_link_key_db_t * btstack_link_key_db = btstack_link_key_db_tlv_get_instance(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
365     hci_set_link_key_db(btstack_link_key_db);
366 
367     // setup LE Device DB using TLV
368     le_device_db_tlv_configure(btstack_tlv_impl, &btstack_tlv_flash_bank_context);
369 
370 #ifdef HAVE_HAL_AUDIO
371     // setup audio
372     btstack_audio_sink_set_instance(btstack_audio_embedded_sink_get_instance());
373     btstack_audio_source_set_instance(btstack_audio_embedded_source_get_instance());
374 #endif
375 
376     // inform about BTstack state
377     hci_event_callback_registration.callback = &packet_handler;
378     hci_add_event_handler(&hci_event_callback_registration);
379 
380     // hand over to btstack embedded code
381     btstack_main(0, NULL);
382 
383     // go
384     btstack_run_loop_execute();
385 }
386 
387 #if 0
388 
389 // Help with debugging hard faults - from FreeRTOS docu
390 // https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html
391 
392 void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress );
393 void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress ) {
394 
395     /* These are volatile to try and prevent the compiler/linker optimising them
396     away as the variables never actually get used.  If the debugger won't show the
397     values of the variables, make them global my moving their declaration outside
398     of this function. */
399     volatile uint32_t r0;
400     volatile uint32_t r1;
401     volatile uint32_t r2;
402     volatile uint32_t r3;
403     volatile uint32_t r12;
404     volatile uint32_t lr; /* Link register. */
405     volatile uint32_t pc; /* Program counter. */
406     volatile uint32_t psr;/* Program status register. */
407 
408     r0  = pulFaultStackAddress[ 0 ];
409     r1  = pulFaultStackAddress[ 1 ];
410     r2  = pulFaultStackAddress[ 2 ];
411     r3  = pulFaultStackAddress[ 3 ];
412 
413     r12 = pulFaultStackAddress[ 4 ];
414     lr  = pulFaultStackAddress[ 5 ];
415     pc  = pulFaultStackAddress[ 6 ];
416     psr = pulFaultStackAddress[ 7 ];
417 
418     /* When the following line is hit, the variables contain the register values. */
419     for( ;; );
420 }
421 
422 /* The prototype shows it is a naked function - in effect this is just an
423 assembly function. */
424 void HardFault_Handler( void ) __attribute__( ( naked ) );
425 
426 /* The fault handler implementation calls a function called
427 prvGetRegistersFromStack(). */
428 void HardFault_Handler(void)
429 {
430     __asm volatile
431     (
432         " tst lr, #4                                                \n"
433         " ite eq                                                    \n"
434         " mrseq r0, msp                                             \n"
435         " mrsne r0, psp                                             \n"
436         " ldr r1, [r0, #24]                                         \n"
437         " ldr r2, handler2_address_const                            \n"
438         " bx r2                                                     \n"
439         " handler2_address_const: .word prvGetRegistersFromStack    \n"
440     );
441 }
442 
443 #endif
444