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