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