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