1 /** 2 * \file 3 * 4 * \brief Getting Started Application. 5 * 6 * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved. 7 * 8 * \asf_license_start 9 * 10 * \page License 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright notice, 16 * this list of conditions and the following disclaimer. 17 * 18 * 2. Redistributions in binary form must reproduce the above copyright notice, 19 * this list of conditions and the following disclaimer in the documentation 20 * and/or other materials provided with the distribution. 21 * 22 * 3. The name of Atmel may not be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * 4. This software may only be redistributed and used in connection with an 26 * Atmel microcontroller product. 27 * 28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 * 40 * \asf_license_stop 41 * 42 */ 43 44 /** 45 * \mainpage Getting Started Application 46 * 47 * \section Purpose 48 * 49 * BTstack port for SAM MCUs 50 * 51 * \section Requirements 52 * 53 * This package can be used with SAM evaluation kits. 54 * 55 * \section Description 56 * 57 * 58 * \section Usage 59 * 60 * -# Build the program and download it inside the evaluation board. 61 * -# On the computer, open and configure a terminal application 62 * (e.g. HyperTerminal on Microsoft Windows) with these settings: 63 * - 115200 bauds 64 * - 8 bits of data 65 * - No parity 66 * - 1 stop bit 67 * - No flow control 68 * -# Start the application. 69 * 70 */ 71 72 #include "asf.h" 73 #include "stdio_serial.h" 74 #include "conf_board.h" 75 #include "conf_clock.h" 76 77 // BTstack 78 #include "btstack_run_loop.h" 79 #include "btstack_run_loop_embedded.h" 80 #include "btstack_debug.h" 81 #include "hci.h" 82 #include "hci_dump.h" 83 #include "btstack_chipset_atwilc3000.h" 84 #include "btstack_memory.h" 85 #include "classic/btstack_link_key_db.h" 86 87 #include "hal_uart_dma.h" 88 #include "hal_cpu.h" 89 #include "hal_tick.h" 90 91 extern int btstack_main(int argc, const char * argv[]); 92 93 #define USE_XDMAC_FOR_USART 94 #define XDMA_CH_UART_TX 0 95 #define XDMA_CH_UART_RX 1 96 97 #define STRING_EOL "\r" 98 #define STRING_HEADER "-- Getting Started Example --\r\n" \ 99 "-- "BOARD_NAME" --\r\n" \ 100 "-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL 101 102 /** All interrupt mask. */ 103 #define ALL_INTERRUPT_MASK 0xffffffff 104 105 static void dummy_handler(void){} 106 static void (*tick_handler)(void) = &dummy_handler; 107 108 /** when porting to different setup, please 109 * disable baudrate change (use 0 instead of 4000000) 110 * and don't enable eHCILL mode (comment line below) 111 */ 112 113 // after HCI Reset, use 115200. Then increase baud rate to X. 114 static hci_transport_config_uart_t hci_transport_config = { 115 HCI_TRANSPORT_CONFIG_UART, 116 115200, 117 4000000, // use 0 to skip baud rate change from 115200 to X for debugging purposes 118 1, // flow control 119 NULL, 120 }; 121 /// @cond 0 122 /**INDENT-OFF**/ 123 #ifdef __cplusplus 124 extern "C" { 125 #endif 126 /**INDENT-ON**/ 127 /// @endcond 128 129 /** 130 * \brief Handler for System Tick interrupt. 131 */ 132 void SysTick_Handler(void) 133 { 134 tick_handler(); 135 } 136 137 /** 138 * Configure UART console. 139 */ 140 // [main_console_configure] 141 static void configure_console(void) 142 { 143 const usart_serial_options_t uart_serial_options = { 144 .baudrate = CONF_UART_BAUDRATE, 145 #ifdef CONF_UART_CHAR_LENGTH 146 .charlength = CONF_UART_CHAR_LENGTH, 147 #endif 148 .paritytype = CONF_UART_PARITY, 149 #ifdef CONF_UART_STOP_BITS 150 .stopbits = CONF_UART_STOP_BITS, 151 #endif 152 }; 153 154 /* Configure console UART. */ 155 sysclk_enable_peripheral_clock(CONSOLE_UART_ID); 156 stdio_serial_init(CONF_UART, &uart_serial_options); 157 } 158 159 // [main_console_configure] 160 161 /** 162 * \brief Wait for the given number of milliseconds (ticks 163 * generated by the SAM's microcontrollers's system tick). 164 * 165 * \param ul_dly_ticks Delay to wait for, in milliseconds. 166 */ 167 // [main_ms_delay] 168 static void mdelay(uint32_t delay_in_ms) 169 { 170 // delay_ms(delay_in_ms); 171 uint32_t time_to_wait = btstack_run_loop_get_time_ms() + delay_in_ms; 172 while (btstack_run_loop_get_time_ms() < time_to_wait); 173 } 174 // [main_ms_delay] 175 176 //////////////////////////////////////////////////////////////////////////////// 177 // hal_cpu.h implementation 178 //////////////////////////////////////////////////////////////////////////////// 179 // hal_led.h implementation 180 #include "hal_led.h" 181 void hal_led_off(void); 182 void hal_led_on(void); 183 184 void hal_led_off(void){ 185 // gpio_set_pin_low(GPIOA, GPIO_LED2); 186 } 187 void hal_led_on(void){ 188 // gpio_set_pin_high(GPIOA, GPIO_LED2); 189 } 190 void hal_led_toggle(void){ 191 // gpio_toggle_pin(GPIOA, GPIO_LED2); 192 } 193 194 // hal_cpu.h implementation 195 #include "hal_cpu.h" 196 197 void hal_cpu_disable_irqs(void){ 198 //__disable_irq(); 199 } 200 201 void hal_cpu_enable_irqs(void){ 202 // __enable_irq(); 203 } 204 205 void hal_cpu_enable_irqs_and_sleep(void){ 206 hal_led_off(); 207 // __enable_irq(); 208 // __asm__("wfe"); // go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag 209 210 // note: hal_uart_needed_during_sleep can be used to disable peripheral clock if it's not needed for a timer 211 hal_led_on(); 212 } 213 214 215 #ifndef USE_XDMAC_FOR_USART 216 // RX state 217 static volatile uint16_t bytes_to_read = 0; 218 static volatile uint8_t * rx_buffer_ptr = 0; 219 220 // TX state 221 static volatile uint16_t bytes_to_write = 0; 222 static volatile uint8_t * tx_buffer_ptr = 0; 223 #endif 224 225 // handlers 226 static void (*rx_done_handler)(void) = dummy_handler; 227 static void (*tx_done_handler)(void) = dummy_handler; 228 static void (*cts_irq_handler)(void) = dummy_handler; 229 230 // @note While the Atmel SAM S7x data sheet states 231 // "The hardware handshaking feature enables an out-of-band flow control by automatic management 232 // of the pins RTS and CTS.", 233 // I didn't see RTS going up automatically up, ever. So, at least for RTS, the automatic management 234 // is just a glorified GPIO pin control feature, which provides no benefit, but irritates a lot 235 236 static void hal_uart_rts_high(void){ 237 BOARD_USART->US_CR = US_CR_RTSEN; 238 } 239 static void hal_uart_rts_low(void){ 240 BOARD_USART->US_CR = US_CR_RTSDIS; 241 } 242 243 /** 244 */ 245 void hal_uart_dma_init(void) 246 { 247 // configure n_shutdown pin, and reset Bluetooth 248 ioport_set_pin_dir(N_SHUTDOWN, IOPORT_DIR_OUTPUT); 249 ioport_set_pin_level(N_SHUTDOWN, IOPORT_PIN_LEVEL_LOW); 250 mdelay(100); 251 ioport_set_pin_level(N_SHUTDOWN, IOPORT_PIN_LEVEL_HIGH); 252 mdelay(500); 253 254 // configure Bluetooth USART 255 const sam_usart_opt_t bluetooth_settings = { 256 115200, 257 US_MR_CHRL_8_BIT, 258 US_MR_PAR_NO, 259 US_MR_NBSTOP_1_BIT, 260 US_MR_CHMODE_NORMAL, 261 /* This field is only used in IrDA mode. */ 262 0 263 }; 264 265 /* Enable the peripheral clock in the PMC. */ 266 sysclk_enable_peripheral_clock(BOARD_ID_USART); 267 268 /* Configure USART mode. */ 269 usart_init_hw_handshaking(BOARD_USART, &bluetooth_settings, sysclk_get_peripheral_hz()); 270 271 /* Disable all the interrupts. */ 272 usart_disable_interrupt(BOARD_USART, ALL_INTERRUPT_MASK); 273 274 // RX not ready yet 275 // usart_drive_RTS_pin_high(BOARD_USART); 276 277 /* Enable TX & RX function. */ 278 usart_enable_tx(BOARD_USART); 279 usart_enable_rx(BOARD_USART); 280 281 /* Configure and enable interrupt of USART. */ 282 NVIC_EnableIRQ(USART_IRQn); 283 284 #ifdef USE_XDMAC_FOR_USART 285 286 // setup XDMAC 287 288 /* Initialize and enable DMA controller */ 289 pmc_enable_periph_clk(ID_XDMAC); 290 291 /* Enable XDMA interrupt */ 292 NVIC_ClearPendingIRQ(XDMAC_IRQn); 293 NVIC_SetPriority( XDMAC_IRQn ,1); 294 NVIC_EnableIRQ(XDMAC_IRQn); 295 296 // Setup XDMA Channel for USART TX 297 xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)&BOARD_USART->US_THR); 298 xdmac_channel_set_config(XDMAC, XDMA_CH_UART_TX, 299 XDMAC_CC_TYPE_PER_TRAN | 300 XDMAC_CC_DSYNC_MEM2PER | 301 XDMAC_CC_MEMSET_NORMAL_MODE | 302 XDMAC_CC_MBSIZE_SINGLE | 303 XDMAC_CC_DWIDTH_BYTE | 304 XDMAC_CC_SIF_AHB_IF0 | 305 XDMAC_CC_DIF_AHB_IF1 | 306 XDMAC_CC_SAM_INCREMENTED_AM | 307 XDMAC_CC_DAM_FIXED_AM | 308 XDMAC_CC_CSIZE_CHK_1 | 309 XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_TX) 310 ); 311 xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_TX, 0); 312 xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0); 313 xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0); 314 xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_TX, 0); 315 xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_TX, 0); 316 xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_TX); 317 xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_TX, XDMAC_CIE_BIE); 318 319 // Setup XDMA Channel for USART RX 320 xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)&BOARD_USART->US_RHR); 321 xdmac_channel_set_config(XDMAC, XDMA_CH_UART_RX, 322 XDMAC_CC_TYPE_PER_TRAN | 323 XDMAC_CC_DSYNC_PER2MEM | 324 XDMAC_CC_MEMSET_NORMAL_MODE | 325 XDMAC_CC_MBSIZE_SINGLE | 326 XDMAC_CC_DWIDTH_BYTE | 327 XDMAC_CC_SIF_AHB_IF1 | 328 XDMAC_CC_DIF_AHB_IF0 | 329 XDMAC_CC_SAM_FIXED_AM | 330 XDMAC_CC_DAM_INCREMENTED_AM | 331 XDMAC_CC_CSIZE_CHK_1 | 332 XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_RX) 333 ); 334 xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_RX, 0); 335 xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0); 336 xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0); 337 xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_RX, 0); 338 xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_RX, 0); 339 xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_RX); 340 xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_RX, XDMAC_CIE_BIE); 341 #endif 342 } 343 344 void hal_uart_dma_set_sleep(uint8_t sleep){ 345 } 346 347 void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){ 348 rx_done_handler = the_block_handler; 349 } 350 351 void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){ 352 tx_done_handler = the_block_handler; 353 } 354 355 void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){ 356 cts_irq_handler = the_irq_handler; 357 } 358 359 int hal_uart_dma_set_baud(uint32_t baud){ 360 /* Disable TX & RX function. */ 361 usart_disable_tx(BOARD_USART); 362 usart_disable_rx(BOARD_USART); 363 uint32_t res = usart_set_async_baudrate(BOARD_USART, baud, sysclk_get_peripheral_hz()); 364 if (res){ 365 log_error("hal_uart_dma_set_baud library call failed"); 366 } 367 368 /* Enable TX & RX function. */ 369 usart_enable_tx(BOARD_USART); 370 usart_enable_rx(BOARD_USART); 371 372 log_info("Bump baud rate"); 373 374 return 0; 375 } 376 377 void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){ 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 tx_buffer_ptr = (uint8_t *) data; 386 bytes_to_write = size; 387 usart_enable_interrupt(BOARD_USART, US_IER_TXRDY); 388 #endif 389 } 390 391 void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){ 392 393 hal_uart_rts_low(); 394 395 #ifdef USE_XDMAC_FOR_USART 396 xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_RX); 397 xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)data); 398 xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_RX, size); 399 xdmac_channel_enable(XDMAC, XDMA_CH_UART_RX); 400 #else 401 rx_buffer_ptr = data; 402 bytes_to_read = size; 403 usart_enable_interrupt(BOARD_USART, US_IER_RXRDY); 404 #endif 405 } 406 407 #ifdef USE_XDMAC_FOR_USART 408 void XDMAC_Handler(void) 409 { 410 uint32_t dma_status; 411 dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_TX); 412 if (dma_status & XDMAC_CIS_BIS) { 413 tx_done_handler(); 414 } 415 dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_RX); 416 if (dma_status & XDMAC_CIS_BIS) { 417 hal_uart_rts_high(); 418 rx_done_handler(); 419 } 420 } 421 #else 422 void USART_Handler(void) 423 { 424 uint32_t ul_status; 425 uint8_t uc_char; 426 427 /* Read USART status. */ 428 ul_status = usart_get_status(BOARD_USART); 429 430 // handle ready to send 431 if(ul_status & US_IER_TXRDY) { 432 if (bytes_to_write){ 433 // send next byte 434 usart_write(BOARD_USART, *tx_buffer_ptr); 435 tx_buffer_ptr++; 436 bytes_to_write--; 437 } else { 438 // done. disable tx ready interrupt to avoid starvation here 439 usart_disable_interrupt(BOARD_USART, US_IER_TXRDY); 440 tx_done_handler(); 441 } 442 } 443 444 // handle byte available for read 445 if (ul_status & US_IER_RXRDY) { 446 uint32_t ch; 447 usart_read(BOARD_USART, (uint32_t *)&ch); 448 *rx_buffer_ptr++ = ch; 449 bytes_to_read--; 450 if (bytes_to_read == 0){ 451 // done. disable rx ready interrupt, raise RTS 452 hal_uart_rts_high(); 453 usart_disable_interrupt(BOARD_USART, US_IER_RXRDY); 454 rx_done_handler(); 455 } 456 } 457 } 458 #endif 459 460 void hal_tick_init() 461 { 462 /* Configure systick for 1 ms */ 463 puts("Configure system tick to get 1ms tick period.\r"); 464 if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) { 465 puts("-F- Systick configuration error\r"); 466 while (1); 467 } 468 } 469 470 void hal_tick_set_handler(void (*handler)(void)){ 471 if (handler == NULL){ 472 tick_handler = &dummy_handler; 473 return; 474 } 475 tick_handler = handler; 476 } 477 478 int hal_tick_get_tick_period_in_ms(void){ 479 return 1; 480 } 481 482 483 /** 484 * \brief getting-started Application entry point. 485 * 486 * \return Unused (ANSI-C compatibility). 487 */ 488 // [main] 489 int main(void) 490 { 491 //! [main_step_sys_init] 492 /* Initialize the SAM system */ 493 sysclk_init(); 494 board_init(); 495 //! [main_step_sys_init] 496 497 //! [main_step_console_init] 498 /* Initialize the console uart */ 499 configure_console(); 500 //! [main_step_console_init] 501 502 /* Output example information */ 503 puts(STRING_HEADER); 504 505 printf("CPU %lu hz, peripheral clock %lu hz\n", sysclk_get_cpu_hz(), sysclk_get_peripheral_hz()); 506 507 // start with BTstack init - especially configure HCI Transport 508 btstack_memory_init(); 509 btstack_run_loop_init(btstack_run_loop_embedded_get_instance()); 510 511 // enable full log output while porting 512 // hci_dump_open(NULL, HCI_DUMP_STDOUT); 513 514 // init HCI 515 // hci_init(hci_transport_h4_instance(), (void*) &hci_transport_config); 516 // hci_set_chipset(btstack_chipset_cc256x_instance()); 517 // hci_set_link_key_db(btstack_link_key_db_memory_instance()); 518 519 // enable eHCILL 520 // bt_control_cc256x_enable_ehcill(1); 521 522 // hand over to btstack embedded code 523 btstack_main(0, NULL); 524 525 // go 526 btstack_run_loop_execute(); 527 528 // compiler happy 529 while(1); 530 } 531 // [main] 532 /// @cond 0 533 /**INDENT-OFF**/ 534 #ifdef __cplusplus 535 } 536 #endif 537 /**INDENT-ON**/ 538 /// @endcond 539