1 #define __BTSTACK_FILE__ "main.c" 2 3 #include "asf.h" 4 #include "stdio_serial.h" 5 #include "conf_board.h" 6 #include "conf_clock.h" 7 8 // BTstack 9 #include "btstack_chipset_atwilc3000.h" 10 #include "btstack_debug.h" 11 #include "btstack_memory.h" 12 #include "btstack_run_loop.h" 13 #include "btstack_run_loop_embedded.h" 14 #include "hal_uart_dma.h" 15 #include "hal_cpu.h" 16 #include "hal_tick.h" 17 #include "hci.h" 18 #include "hci_dump.h" 19 #include "hci_dump_embedded_stdout.h" 20 #include "wilc3000_ble_firmware.h" 21 22 // #define USE_XDMAC_FOR_USART 23 #define XDMA_CH_UART_TX 0 24 #define XDMA_CH_UART_RX 1 25 26 /** All interrupt mask. */ 27 #define ALL_INTERRUPT_MASK 0xffffffff 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 extern int btstack_main(int argc, const char * argv[]); 34 35 static void dummy_handler(void){} 36 static void (*tick_handler)(void) = &dummy_handler; 37 38 static btstack_uart_config_t uart_config; 39 40 static hci_transport_config_uart_t transport_config = { 41 HCI_TRANSPORT_CONFIG_UART, 42 2000000, // directly use high baud rate after config 43 0, // use 0 to skip baud rate change from 115200 to X for debugging purposes 44 1, // flow control 45 NULL, 46 }; 47 48 /** 49 * \brief Handler for System Tick interrupt. 50 */ 51 void SysTick_Handler(void) 52 { 53 tick_handler(); 54 } 55 56 // Debug console Output 57 58 /** 59 * Configure UART console. 60 */ 61 // [main_console_configure] 62 static void configure_console(void) 63 { 64 const usart_serial_options_t uart_serial_options = { 65 .baudrate = CONF_UART_BAUDRATE, 66 #ifdef CONF_UART_CHAR_LENGTH 67 .charlength = CONF_UART_CHAR_LENGTH, 68 #endif 69 .paritytype = CONF_UART_PARITY, 70 #ifdef CONF_UART_STOP_BITS 71 .stopbits = CONF_UART_STOP_BITS, 72 #endif 73 }; 74 75 /* Configure console UART. */ 76 sysclk_enable_peripheral_clock(CONSOLE_UART_ID); 77 stdio_serial_init(CONF_UART, &uart_serial_options); 78 } 79 80 // Debug console Input 81 82 #include "btstack_stdin.h" 83 84 static void (*stdin_handler)(char c); 85 static btstack_data_source_t stdin_data_source; 86 87 static void btstack_stdin_process(struct btstack_data_source *ds, btstack_data_source_callback_type_t callback_type){ 88 // try to read from console 89 uint32_t stdin_character; 90 uint32_t res = usart_read(CONF_UART, &stdin_character); 91 if (res) return; 92 93 if (stdin_handler){ 94 (*stdin_handler)(stdin_character & 0xff); 95 } 96 } 97 98 void btstack_stdin_setup(void (*handler)(char c)){ 99 // set handler 100 stdin_handler = handler; 101 102 // set up polling data_source 103 btstack_run_loop_set_data_source_handler(&stdin_data_source, &btstack_stdin_process); 104 btstack_run_loop_enable_data_source_callbacks(&stdin_data_source, DATA_SOURCE_CALLBACK_POLL); 105 btstack_run_loop_add_data_source(&stdin_data_source); 106 } 107 108 // [main_console_configure] 109 110 /** 111 * \brief Wait for the given number of milliseconds (ticks 112 * generated by the SAM's microcontrollers's system tick). 113 * 114 * \param ul_dly_ticks Delay to wait for, in milliseconds. 115 */ 116 // [main_ms_delay] 117 static void mdelay(uint32_t delay_in_ms) 118 { 119 // delay_ms(delay_in_ms); 120 uint32_t time_to_wait = btstack_run_loop_get_time_ms() + delay_in_ms; 121 while (btstack_run_loop_get_time_ms() < time_to_wait); 122 } 123 // [main_ms_delay] 124 125 //////////////////////////////////////////////////////////////////////////////// 126 // hal_cpu.h implementation 127 //////////////////////////////////////////////////////////////////////////////// 128 // hal_led.h implementation 129 #include "hal_led.h" 130 void hal_led_off(void); 131 void hal_led_on(void); 132 133 void hal_led_off(void){ 134 // gpio_set_pin_low(GPIOA, GPIO_LED2); 135 } 136 void hal_led_on(void){ 137 // gpio_set_pin_high(GPIOA, GPIO_LED2); 138 } 139 void hal_led_toggle(void){ 140 // gpio_toggle_pin(GPIOA, GPIO_LED2); 141 } 142 143 // hal_cpu.h implementation 144 #include "hal_cpu.h" 145 146 void hal_cpu_disable_irqs(void){ 147 //__disable_irq(); 148 } 149 150 void hal_cpu_enable_irqs(void){ 151 // __enable_irq(); 152 } 153 154 void hal_cpu_enable_irqs_and_sleep(void){ 155 hal_led_off(); 156 // __enable_irq(); 157 // __asm__("wfe"); // go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag 158 159 // note: hal_uart_needed_during_sleep can be used to disable peripheral clock if it's not needed for a timer 160 hal_led_on(); 161 } 162 163 164 #ifndef USE_XDMAC_FOR_USART 165 // RX state 166 static volatile uint16_t bytes_to_read = 0; 167 static volatile uint8_t * rx_buffer_ptr = 0; 168 169 // TX state 170 static volatile uint16_t bytes_to_write = 0; 171 static volatile uint8_t * tx_buffer_ptr = 0; 172 #endif 173 174 static volatile int rx_notify; 175 static volatile int tx_notify; 176 177 static int simulate_flowcontrol; 178 179 // handlers 180 static void (*rx_done_handler)(void) = dummy_handler; 181 static void (*tx_done_handler)(void) = dummy_handler; 182 static void (*cts_irq_handler)(void) = dummy_handler; 183 184 // @note While the Atmel SAM S7x data sheet states 185 // "The hardware handshaking feature enables an out-of-band flow control by automatic management 186 // of the pins RTS and CTS.", 187 // I didn't see RTS going up automatically up, ever. So, at least for RTS, the automatic management 188 // is just a glorified GPIO pin control feature, which provides no benefit, but irritates a lot 189 190 // J505:6 191 #define DEBUG_PIN_1 PIO_PD16_IDX 192 // J505:5 193 #define DEBUG_PIN_2 PIO_PD15_IDX 194 195 static inline void hal_uart_rts_high(void){ 196 if (!simulate_flowcontrol) return; 197 ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_HIGH); 198 BOARD_USART->US_CR = US_CR_RTSEN; 199 } 200 static inline void hal_uart_rts_low(void){ 201 if (!simulate_flowcontrol) return; 202 ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_LOW); 203 BOARD_USART->US_CR = US_CR_RTSDIS; 204 } 205 206 /** 207 */ 208 static int hal_uart_dma_initialized = 0; 209 void hal_uart_dma_init(void) 210 { 211 if (hal_uart_dma_initialized){ 212 log_info("hal_uart_dma_init already initialized"); 213 return; 214 } 215 hal_uart_dma_initialized = 1; 216 217 // debug 218 #ifdef DEBUG_PIN_1 219 ioport_set_pin_dir(DEBUG_PIN_1, IOPORT_DIR_OUTPUT); 220 ioport_set_pin_level(DEBUG_PIN_1, IOPORT_PIN_LEVEL_LOW); 221 #endif 222 #ifdef DEBUG_PIN_2 223 ioport_set_pin_dir(DEBUG_PIN_2, IOPORT_DIR_OUTPUT); 224 ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_LOW); 225 #endif 226 // power on 227 ioport_set_pin_dir(BLUETOOTH_CHP_EN, IOPORT_DIR_OUTPUT); 228 ioport_set_pin_level(BLUETOOTH_CHP_EN, IOPORT_PIN_LEVEL_HIGH); 229 230 // reset 231 ioport_set_pin_dir(BLUETOOTH_RESET, IOPORT_DIR_OUTPUT); 232 ioport_set_pin_level(BLUETOOTH_RESET, IOPORT_PIN_LEVEL_LOW); 233 mdelay(250); 234 ioport_set_pin_level(BLUETOOTH_RESET, IOPORT_PIN_LEVEL_HIGH); 235 mdelay(250); 236 237 /* Enable the peripheral clock in the PMC. */ 238 sysclk_enable_peripheral_clock(BOARD_ID_USART); 239 240 // configure Bluetooth USART 241 const sam_usart_opt_t bluetooth_settings = { 242 115200, 243 US_MR_CHRL_8_BIT, 244 US_MR_PAR_NO, 245 US_MR_NBSTOP_1_BIT, 246 US_MR_CHMODE_NORMAL, 247 /* This field is only used in IrDA mode. */ 248 0 249 }; 250 251 /* Configure USART mode. */ 252 simulate_flowcontrol = 0; 253 usart_init_rs232(BOARD_USART, &bluetooth_settings, sysclk_get_peripheral_hz()); 254 // Set RTS = 0 (normal mode) 255 BOARD_USART->US_CR = US_CR_RTSEN; 256 257 /* Disable all the interrupts. */ 258 usart_disable_interrupt(BOARD_USART, ALL_INTERRUPT_MASK); 259 260 /* Enable TX & RX function. */ 261 usart_enable_tx(BOARD_USART); 262 usart_enable_rx(BOARD_USART); 263 264 /* Configure and enable interrupt of USART. */ 265 NVIC_EnableIRQ(USART_IRQn); 266 267 #ifdef USE_XDMAC_FOR_USART 268 269 // setup XDMAC 270 271 /* Initialize and enable DMA controller */ 272 pmc_enable_periph_clk(ID_XDMAC); 273 274 /* Enable XDMA interrupt */ 275 NVIC_ClearPendingIRQ(XDMAC_IRQn); 276 NVIC_SetPriority( XDMAC_IRQn ,1); 277 NVIC_EnableIRQ(XDMAC_IRQn); 278 279 // Setup XDMA Channel for USART TX 280 xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)&BOARD_USART->US_THR); 281 xdmac_channel_set_config(XDMAC, XDMA_CH_UART_TX, 282 XDMAC_CC_TYPE_PER_TRAN | 283 XDMAC_CC_DSYNC_MEM2PER | 284 XDMAC_CC_MEMSET_NORMAL_MODE | 285 XDMAC_CC_MBSIZE_SINGLE | 286 XDMAC_CC_DWIDTH_BYTE | 287 XDMAC_CC_SIF_AHB_IF0 | 288 XDMAC_CC_DIF_AHB_IF1 | 289 XDMAC_CC_SAM_INCREMENTED_AM | 290 XDMAC_CC_DAM_FIXED_AM | 291 XDMAC_CC_CSIZE_CHK_1 | 292 XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_TX) 293 ); 294 xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_TX, 0); 295 xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0); 296 xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0); 297 xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_TX, 0); 298 xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_TX, 0); 299 xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_TX); 300 xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_TX, XDMAC_CIE_BIE); 301 302 // Setup XDMA Channel for USART RX 303 xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)&BOARD_USART->US_RHR); 304 xdmac_channel_set_config(XDMAC, XDMA_CH_UART_RX, 305 XDMAC_CC_TYPE_PER_TRAN | 306 XDMAC_CC_DSYNC_PER2MEM | 307 XDMAC_CC_MEMSET_NORMAL_MODE | 308 XDMAC_CC_MBSIZE_SINGLE | 309 XDMAC_CC_DWIDTH_BYTE | 310 XDMAC_CC_SIF_AHB_IF1 | 311 XDMAC_CC_DIF_AHB_IF0 | 312 XDMAC_CC_SAM_FIXED_AM | 313 XDMAC_CC_DAM_INCREMENTED_AM | 314 XDMAC_CC_CSIZE_CHK_1 | 315 XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_RX) 316 ); 317 xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_RX, 0); 318 xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0); 319 xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0); 320 xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_RX, 0); 321 xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_RX, 0); 322 xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_RX); 323 xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_RX, XDMAC_CIE_BIE); 324 #endif 325 } 326 327 void hal_uart_dma_set_sleep(uint8_t sleep){ 328 } 329 330 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){ 331 rx_done_handler = the_block_handler; 332 } 333 334 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){ 335 tx_done_handler = the_block_handler; 336 } 337 338 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){ 339 cts_irq_handler = the_irq_handler; 340 } 341 342 int hal_uart_dma_set_baud(uint32_t baud){ 343 /* Disable TX & RX function. */ 344 usart_disable_tx(BOARD_USART); 345 usart_disable_rx(BOARD_USART); 346 uint32_t res = usart_set_async_baudrate(BOARD_USART, baud, sysclk_get_peripheral_hz()); 347 if (res){ 348 log_error("hal_uart_dma_set_baud library call failed"); 349 } 350 351 /* Enable TX & RX function. */ 352 usart_enable_tx(BOARD_USART); 353 usart_enable_rx(BOARD_USART); 354 355 log_info("set baud rate %u", (int) baud); 356 return 0; 357 } 358 359 int hal_uart_dma_set_flowcontrol(int flowcontrol){ 360 log_info("hal_uart_dma_set_flowcontrol %u", flowcontrol); 361 simulate_flowcontrol = flowcontrol; 362 if (flowcontrol){ 363 /* Set hardware handshaking mode. */ 364 BOARD_USART->US_MR = (BOARD_USART->US_MR & ~US_MR_USART_MODE_Msk) | US_MR_USART_MODE_HW_HANDSHAKING; 365 hal_uart_rts_high(); 366 } else { 367 /* Set nomal mode. */ 368 BOARD_USART->US_MR = (BOARD_USART->US_MR & ~US_MR_USART_MODE_Msk) | US_MR_USART_MODE_NORMAL; 369 // Set RTS = 0 (normal mode) 370 BOARD_USART->US_CR = US_CR_RTSEN; 371 } 372 return 0; 373 } 374 375 void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){ 376 377 tx_notify = 1; 378 379 #ifdef USE_XDMAC_FOR_USART 380 xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_TX); 381 xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)data); 382 xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_TX, size); 383 xdmac_channel_enable(XDMAC, XDMA_CH_UART_TX); 384 #else 385 if (bytes_to_write){ 386 log_error("send block, bytes to write %u", bytes_to_write); 387 return; 388 } 389 tx_buffer_ptr = (uint8_t *) data; 390 bytes_to_write = size; 391 usart_enable_interrupt(BOARD_USART, US_IER_TXRDY); 392 #endif 393 } 394 395 void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){ 396 397 #ifdef DEBUG_PIN_1 398 ioport_set_pin_level(DEBUG_PIN_1, IOPORT_PIN_LEVEL_HIGH); 399 #endif 400 401 hal_uart_rts_low(); 402 403 rx_notify = 1; 404 405 #ifdef USE_XDMAC_FOR_USART 406 xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_RX); 407 xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)data); 408 xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_RX, size); 409 xdmac_channel_enable(XDMAC, XDMA_CH_UART_RX); 410 #else 411 rx_buffer_ptr = data; 412 bytes_to_read = size; 413 usart_enable_interrupt(BOARD_USART, US_IER_RXRDY); 414 #endif 415 } 416 417 #ifdef USE_XDMAC_FOR_USART 418 void XDMAC_Handler(void) 419 { 420 uint32_t dma_status; 421 dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_TX); 422 if (dma_status & XDMAC_CIS_BIS) { 423 if (tx_notify){ 424 tx_notify = 0; 425 tx_done_handler(); 426 } 427 } 428 dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_RX); 429 if (dma_status & XDMAC_CIS_BIS) { 430 hal_uart_rts_high(); 431 if (rx_notify){ 432 rx_notify = 0; 433 rx_done_handler(); 434 } 435 } 436 } 437 #else 438 void USART_Handler(void) 439 { 440 441 #ifdef DEBUG_PIN_2 442 // ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_HIGH); 443 #endif 444 445 /* Read USART status. */ 446 uint32_t ul_status = usart_get_status(BOARD_USART); 447 448 // handle ready to send 449 if(ul_status & US_IER_TXRDY) { 450 if (bytes_to_write){ 451 // send next byte 452 usart_write(BOARD_USART, *tx_buffer_ptr); 453 tx_buffer_ptr++; 454 bytes_to_write--; 455 } else { 456 457 // done. disable tx ready interrupt to avoid starvation here 458 usart_disable_interrupt(BOARD_USART, US_IER_TXRDY); 459 if (tx_notify){ 460 tx_notify = 0; 461 tx_done_handler(); 462 } 463 } 464 } 465 466 // handle byte available for read 467 if (ul_status & US_IER_RXRDY) { 468 if (bytes_to_read){ 469 uint32_t ch; 470 usart_read(BOARD_USART, (uint32_t *)&ch); 471 *rx_buffer_ptr++ = ch; 472 bytes_to_read--; 473 if (bytes_to_read == 0){ 474 475 #ifdef DEBUG_PIN_1 476 ioport_set_pin_level(DEBUG_PIN_1, IOPORT_PIN_LEVEL_LOW); 477 #endif 478 479 // done. disable rx ready interrupt, raise RTS 480 hal_uart_rts_high(); 481 usart_disable_interrupt(BOARD_USART, US_IER_RXRDY); 482 if (rx_notify){ 483 rx_notify = 0; 484 rx_done_handler(); 485 } 486 } 487 } else { 488 // shoult not happen, disable irq anyway 489 usart_disable_interrupt(BOARD_USART, US_IER_RXRDY); 490 } 491 } 492 #ifdef DEBUG_PIN_2 493 // ioport_set_pin_level(DEBUG_PIN_2, IOPORT_PIN_LEVEL_LOW); 494 #endif 495 496 } 497 #endif 498 499 void hal_tick_init() 500 { 501 /* Configure systick for 1 ms */ 502 puts("Configure system tick to get 1ms tick period.\r"); 503 if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) { 504 puts("-F- Systick configuration error\r"); 505 while (1); 506 } 507 } 508 509 void hal_tick_set_handler(void (*handler)(void)){ 510 if (handler == NULL){ 511 tick_handler = &dummy_handler; 512 return; 513 } 514 tick_handler = handler; 515 } 516 517 int hal_tick_get_tick_period_in_ms(void){ 518 return 1; 519 } 520 521 static const btstack_uart_block_t * uart_driver; 522 523 static void phase2(int status){ 524 525 if (status){ 526 printf("Download firmware failed\n"); 527 return; 528 } 529 530 printf("Phase 2: Main app\n"); 531 532 // init HCI 533 const hci_transport_t * transport = hci_transport_h4_instance(uart_driver); 534 hci_init(transport, (void*) &transport_config); 535 hci_set_chipset(btstack_chipset_atwilc3000_instance()); 536 537 // setup app 538 btstack_main(0, NULL); 539 } 540 541 /** 542 * \brief getting-started Application entry point. 543 * 544 * \return Unused (ANSI-C compatibility). 545 */ 546 // [main] 547 int main(void) 548 { 549 /* Initialize the SAM system */ 550 sysclk_init(); 551 board_init(); 552 553 /* Initialize the console uart */ 554 configure_console(); 555 556 /* Output boot info */ 557 printf("BTstack on SAMV71 Xplained Ultra with ATWILC3000\n"); 558 printf("CPU %lu hz, peripheral clock %lu hz\n", sysclk_get_cpu_hz(), sysclk_get_peripheral_hz()); 559 #ifdef USE_XDMAC_FOR_USART 560 printf("Using XDMA for Bluetooth UART\n"); 561 #else 562 printf("Using IRQ driver for Bluetooth UART\n"); 563 #endif 564 printf("--\n"); 565 566 // start with BTstack init - especially configure HCI Transport 567 btstack_memory_init(); 568 btstack_run_loop_init(btstack_run_loop_embedded_get_instance()); 569 570 // enable full log output while porting 571 // hci_dump_init(hci_dump_embedded_stdout_get_instance()); 572 573 // setup UART HAL + Run Loop integration 574 uart_driver = btstack_uart_block_embedded_instance(); 575 576 // extract UART config from transport config, but disable flow control and use default baudrate 577 uart_config.baudrate = HCI_DEFAULT_BAUDRATE; 578 uart_config.flowcontrol = 0; 579 uart_config.device_name = transport_config.device_name; 580 uart_driver->init(&uart_config); 581 582 // phase #1 download firmware 583 printf("Phase 1: Download firmware\n"); 584 585 // phase #2 start main app 586 btstack_chipset_atwilc3000_download_firmware(uart_driver, transport_config.baudrate_init, transport_config.flowcontrol, (const uint8_t *) firmware_ble, sizeof(firmware_ble), &phase2); 587 588 // go 589 btstack_run_loop_execute(); 590 591 // compiler happy 592 while(1); 593 } 594 #ifdef __cplusplus 595 } 596 #endif 597