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