1 // 2 // BTstack port for Apolle 2 EVB with EM9304 shield 3 // 4 5 #include "am_mcu_apollo.h" 6 #include "am_bsp.h" 7 #include "am_util.h" 8 #include "am_devices_em9304.h" 9 10 //***************************************************************************** 11 // 12 // Insert compiler version at compile time. 13 // 14 //***************************************************************************** 15 #define STRINGIZE_VAL(n) STRINGIZE_VAL2(n) 16 #define STRINGIZE_VAL2(n) #n 17 18 #ifdef __GNUC__ 19 #define COMPILER_VERSION ("GCC " __VERSION__) 20 #elif defined(__ARMCC_VERSION) 21 #define COMPILER_VERSION ("ARMCC " STRINGIZE_VAL(__ARMCC_VERSION)) 22 #elif defined(__KEIL__) 23 #define COMPILER_VERSION "KEIL_CARM " STRINGIZE_VAL(__CA__) 24 #elif defined(__IAR_SYSTEMS_ICC__) 25 #define COMPILER_VERSION __VERSION__ 26 #else 27 #define COMPILER_VERSION "Compiler unknown" 28 #endif 29 30 //***************************************************************************** 31 // 32 // IOM SPI Configuration for EM9304 33 // 34 //***************************************************************************** 35 const am_hal_iom_config_t g_sEm9304IOMConfigSPI = 36 { 37 .ui32ClockFrequency = AM_HAL_IOM_8MHZ, 38 .ui32InterfaceMode = AM_HAL_IOM_SPIMODE, 39 .ui8WriteThreshold = 20, 40 .ui8ReadThreshold = 20, 41 .bSPHA = 0, 42 .bSPOL = 0, 43 }; 44 45 //***************************************************************************** 46 // 47 // UART configuration settings. 48 // 49 //***************************************************************************** 50 am_hal_uart_config_t g_sUartConfig = 51 { 52 .ui32BaudRate = 115200, 53 .ui32DataBits = AM_HAL_UART_DATA_BITS_8, 54 .bTwoStopBits = false, 55 .ui32Parity = AM_HAL_UART_PARITY_NONE, 56 .ui32FlowCtrl = AM_HAL_UART_FLOW_CTRL_NONE, 57 }; 58 59 //***************************************************************************** 60 // 61 // Initialize the UART 62 // 63 //***************************************************************************** 64 void 65 uart_init(uint32_t ui32Module) 66 { 67 // 68 // Make sure the UART RX and TX pins are enabled. 69 // 70 am_bsp_pin_enable(COM_UART_TX); 71 am_bsp_pin_enable(COM_UART_RX); 72 73 // 74 // Power on the selected UART 75 // 76 am_hal_uart_pwrctrl_enable(ui32Module); 77 78 // 79 // Start the UART interface, apply the desired configuration settings, and 80 // enable the FIFOs. 81 // 82 am_hal_uart_clock_enable(ui32Module); 83 84 // 85 // Disable the UART before configuring it. 86 // 87 am_hal_uart_disable(ui32Module); 88 89 // 90 // Configure the UART. 91 // 92 am_hal_uart_config(ui32Module, &g_sUartConfig); 93 94 // 95 // Enable the UART FIFO. 96 // 97 am_hal_uart_fifo_config(ui32Module, AM_HAL_UART_TX_FIFO_1_2 | AM_HAL_UART_RX_FIFO_1_2); 98 99 // 100 // Enable the UART. 101 // 102 am_hal_uart_enable(ui32Module); 103 } 104 105 //***************************************************************************** 106 // 107 // Disable the UART 108 // 109 //***************************************************************************** 110 void 111 uart_disable(uint32_t ui32Module) 112 { 113 // 114 // Clear all interrupts before sleeping as having a pending UART interrupt 115 // burns power. 116 // 117 am_hal_uart_int_clear(ui32Module, 0xFFFFFFFF); 118 119 // 120 // Disable the UART. 121 // 122 am_hal_uart_disable(ui32Module); 123 124 // 125 // Disable the UART pins. 126 // 127 am_bsp_pin_disable(COM_UART_TX); 128 am_bsp_pin_disable(COM_UART_RX); 129 130 // 131 // Disable the UART clock. 132 // 133 am_hal_uart_clock_disable(ui32Module); 134 } 135 136 //***************************************************************************** 137 // 138 // Initialize the EM9304 BLE Controller 139 // 140 //***************************************************************************** 141 void 142 am_devices_em9304_spi_init(uint32_t ui32Module, const am_hal_iom_config_t *psIomConfig) 143 { 144 if ( AM_REGn(IOMSTR, ui32Module, CFG) & AM_REG_IOMSTR_CFG_IFCEN_M ) 145 { 146 return; 147 } 148 149 #if defined(AM_PART_APOLLO2) 150 am_hal_iom_pwrctrl_enable(ui32Module); 151 #endif 152 // 153 // Setup the pins for SPI mode. 154 // 155 am_bsp_iom_spi_pins_enable(ui32Module); 156 157 // 158 // Set the required configuration settings for the IOM. 159 // 160 am_hal_iom_config(ui32Module, psIomConfig); 161 162 // Enable spi 163 am_hal_iom_enable(ui32Module); 164 } 165 166 void 167 configure_em9304_pins(void) 168 { 169 am_bsp_pin_enable(EM9304_CS); 170 am_bsp_pin_enable(EM9304_INT); 171 172 am_hal_gpio_out_bit_set(AM_BSP_GPIO_EM9304_CS); 173 174 am_hal_gpio_int_polarity_bit_set(AM_BSP_GPIO_EM9304_INT, AM_HAL_GPIO_RISING); 175 am_hal_gpio_int_clear(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); 176 am_hal_gpio_int_enable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); 177 } 178 179 void 180 em9304_init(void) 181 { 182 // 183 // Assert RESET to the Telink device. 184 // 185 am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_RESET, AM_HAL_GPIO_OUTPUT); 186 am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_RESET); 187 188 // 189 // Setup SPI interface for EM9304 190 // 191 configure_em9304_pins(); 192 am_devices_em9304_spi_init(AM_BSP_EM9304_IOM, &g_sEm9304IOMConfigSPI); 193 194 // 195 // Delay for 20ms to make sure the em device gets ready for commands. 196 // 197 am_util_delay_ms(5); 198 199 // 200 // Enable the IOM and GPIO interrupt handlers. 201 // 202 am_hal_gpio_out_bit_set(AM_BSP_GPIO_EM9304_RESET); 203 204 am_util_delay_ms(20); 205 } 206 207 // hal_cpu.h implementation 208 #include "hal_cpu.h" 209 210 void hal_cpu_disable_irqs(void){ 211 am_hal_interrupt_master_disable(); 212 } 213 214 void hal_cpu_enable_irqs(void){ 215 am_hal_interrupt_master_enable(); 216 } 217 218 void hal_cpu_enable_irqs_and_sleep(void){ 219 am_hal_interrupt_master_enable(); 220 __asm__("wfe"); // go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag 221 } 222 223 224 // hal_time_ms.h 225 #include "hal_time_ms.h" 226 uint32_t hal_time_ms(void){ 227 return am_hal_stimer_counter_get(); 228 } 229 230 231 /** 232 * Use USART_CONSOLE as a console. 233 * This is a syscall for newlib 234 * @param file 235 * @param ptr 236 * @param len 237 * @return 238 */ 239 #include <stdio.h> 240 #include <unistd.h> 241 #include <errno.h> 242 int _write(int file, char *ptr, int len); 243 int _write(int file, char *ptr, int len){ 244 #if 1 245 uint8_t cr = '\r'; 246 int i; 247 248 if (file == STDOUT_FILENO || file == STDERR_FILENO) { 249 for (i = 0; i < len; i++) { 250 if (ptr[i] == '\n') { 251 am_hal_uart_char_transmit_polled( AM_BSP_UART_PRINT_INST, cr ); 252 } 253 am_hal_uart_char_transmit_polled( AM_BSP_UART_PRINT_INST, ptr[i]); 254 } 255 return i; 256 } 257 errno = EIO; 258 return -1; 259 #else 260 return len; 261 #endif 262 } 263 int _read(int file, char * ptr, int len){ 264 (void)file; 265 (void)ptr; 266 (void)len; 267 return -1; 268 } 269 270 int _close(int file){ 271 (void)file; 272 return -1; 273 } 274 275 int _isatty(int file){ 276 (void)file; 277 return -1; 278 } 279 280 int _lseek(int file){ 281 (void)file; 282 return -1; 283 } 284 285 int _fstat(int file){ 286 (void)file; 287 return -1; 288 } 289 290 void * _sbrk(intptr_t increment){ 291 return (void*) -1; 292 } 293 294 295 // hal_em9304_spi.h 296 #include "hal_em9304_spi.h" 297 298 static void (*hal_em9304_spi_transfer_done_callback)(void); 299 static void (*hal_em9304_spi_ready_callback)(void); 300 301 #if (0 == AM_BSP_EM9304_IOM) 302 void 303 am_iomaster0_isr(void) 304 { 305 uint32_t ui32IntStatus; 306 307 // 308 // Read and clear the interrupt status. 309 // 310 ui32IntStatus = am_hal_iom_int_status_get(0, false); 311 am_hal_iom_int_clear(0, ui32IntStatus); 312 313 // 314 // Service FIFO interrupts as necessary, and call IOM callbacks as 315 // transfers are completed. 316 // 317 am_hal_iom_int_service(0, ui32IntStatus); 318 } 319 #endif 320 321 #if defined(AM_PART_APOLLO2) 322 #if (5 == AM_BSP_EM9304_IOM) 323 void 324 am_iomaster5_isr(void) 325 { 326 uint32_t ui32IntStatus; 327 328 // 329 // Read and clear the interrupt status. 330 // 331 ui32IntStatus = am_hal_iom_int_status_get(5, false); 332 am_hal_iom_int_clear(5, ui32IntStatus); 333 334 // 335 // Service FIFO interrupts as necessary, and call IOM callbacks as 336 // transfers are completed. 337 // 338 am_hal_iom_int_service(5, ui32IntStatus); 339 } 340 #endif 341 #endif 342 343 void 344 am_gpio_isr(void) 345 { 346 uint64_t ui64Status; 347 348 // 349 // Check and clear the GPIO interrupt status 350 // 351 ui64Status = am_hal_gpio_int_status_get(true); 352 am_hal_gpio_int_clear(ui64Status); 353 354 // 355 // Check to see if this was a wakeup event from the BLE radio. 356 // 357 if ( ui64Status & AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT) ) 358 { 359 if (hal_em9304_spi_ready_callback){ 360 (*hal_em9304_spi_ready_callback)(); 361 } 362 } 363 } 364 365 void hal_em9304_spi_enable_ready_interrupt(void){ 366 am_hal_gpio_int_enable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); 367 } 368 369 void hal_em9304_spi_disable_ready_interrupt(void){ 370 am_hal_gpio_int_disable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); 371 } 372 373 void hal_em9304_spi_set_ready_callback(void (*done)(void)){ 374 hal_em9304_spi_ready_callback = done; 375 } 376 377 int hal_em9304_spi_get_ready(void){ 378 return am_hal_gpio_input_read() & AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT); 379 } 380 381 void hal_em9304_spi_init(void){ 382 hal_em9304_spi_disable_ready_interrupt(); 383 } 384 385 void hal_em9304_spi_deinit(void){ 386 hal_em9304_spi_disable_ready_interrupt(); 387 } 388 389 void hal_em9304_spi_set_transfer_done_callback(void (*done)(void)){ 390 hal_em9304_spi_transfer_done_callback = done; 391 } 392 393 void hal_em9304_spi_set_chip_select(int enable){ 394 if (enable){ 395 am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_CS); 396 } else { 397 am_hal_gpio_out_bit_set(AM_BSP_GPIO_EM9304_CS); 398 } 399 } 400 401 void hal_em9304_spi_transceive(const uint8_t * tx_data, uint8_t * rx_data, uint16_t len){ 402 // TODO: handle tx_data/rx_data not aligned 403 // TODO: support non-blocking full duplex 404 uint32_t ui32ChipSelect = 0; 405 // TODO: Use Full Duplex with Interrupt callback 406 // NOTE: Full Duplex only supported on Apollo2 407 // NOTE: Enabling Full Duplex causes am_hal_iom_spi_write_nq to block (as bytes ready returns number of bytes written) 408 // AM_REGn(IOMSTR, ui32Module, CFG) |= AM_REG_IOMSTR_CFG_FULLDUP(1); 409 am_hal_iom_spi_fullduplex_nq(AM_BSP_EM9304_IOM, ui32ChipSelect, (uint32_t *) tx_data, (uint32_t *) rx_data, len, AM_HAL_IOM_RAW); 410 (*hal_em9304_spi_transfer_done_callback)(); 411 return; 412 } 413 414 void hal_em9304_spi_transmit(const uint8_t * tx_data, uint16_t len){ 415 // TODO: handle tx_data/rx_data not aligned 416 uint32_t ui32ChipSelect = 0; 417 am_hal_iom_spi_write_nb(AM_BSP_EM9304_IOM, ui32ChipSelect, (uint32_t *) tx_data, len, AM_HAL_IOM_RAW, hal_em9304_spi_transfer_done_callback); 418 } 419 420 void hal_em9304_spi_receive(uint8_t * rx_data, uint16_t len){ 421 // TODO: handle tx_data/rx_data not aligned 422 // TODO: support non-blocking full duplex 423 uint32_t ui32ChipSelect = 0; 424 am_hal_iom_spi_read_nb(AM_BSP_EM9304_IOM, ui32ChipSelect, (uint32_t *) rx_data, len, AM_HAL_IOM_RAW, hal_em9304_spi_transfer_done_callback); 425 } 426 427 int hal_em9304_spi_get_fullduplex_support(void){ 428 return 0; 429 } 430 431 //***************************************************************************** 432 // 433 // Main 434 // 435 //***************************************************************************** 436 437 438 // EM 9304 SPI Master HCI Implementation 439 const uint8_t hci_reset_2[] = { 0x01, 0x03, 0x0c, 0x00 }; 440 441 #include "btstack_event.h" 442 #include "btstack_memory.h" 443 #include "btstack_run_loop.h" 444 #include "btstack_run_loop_embedded.h" 445 #include "hci_dump.h" 446 #include "hci_dump_embedded_stdout.h" 447 448 static btstack_packet_callback_registration_t hci_event_callback_registration; 449 int btstack_main(int argc, char ** argv); 450 451 // main.c 452 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 453 UNUSED(size); 454 UNUSED(channel); 455 if (packet_type != HCI_EVENT_PACKET) return; 456 switch(hci_event_packet_get_type(packet)){ 457 case BTSTACK_EVENT_STATE: 458 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return; 459 printf("BTstack up and running.\n"); 460 break; 461 default: 462 break; 463 } 464 } 465 466 int main(void) 467 { 468 // 469 // Set the clock frequency. 470 // 471 am_hal_clkgen_sysclk_select(AM_HAL_CLKGEN_SYSCLK_MAX); 472 473 // 474 // Set the default cache configuration 475 // 476 am_hal_cachectrl_enable(&am_hal_cachectrl_defaults); 477 478 // 479 // Configure the board for low power operation. 480 // 481 am_bsp_low_power_init(); 482 483 // 484 // Initialize the printf interface for UART output. 485 // 486 am_util_stdio_printf_init((am_util_stdio_print_char_t)am_bsp_uart_string_print); 487 488 // 489 // Configure and enable the UART. 490 // 491 uart_init(AM_BSP_UART_PRINT_INST); 492 493 // 494 // Reboot and configure em9304. 495 // 496 em9304_init(); 497 498 am_hal_interrupt_enable(AM_HAL_INTERRUPT_GPIO); 499 500 // 501 // Enable IOM SPI interrupts. 502 // 503 am_hal_iom_int_clear(AM_BSP_EM9304_IOM, AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_THR); 504 am_hal_iom_int_enable(AM_BSP_EM9304_IOM, AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_THR); 505 506 #if (0 == AM_BSP_EM9304_IOM) 507 am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOMASTER0); 508 #elif (5 == AM_BSP_EM9304_IOM) 509 am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOMASTER5); 510 #endif 511 512 // Start System Timer (only Apollo 2) 513 am_hal_stimer_config(AM_HAL_STIMER_LFRC_1KHZ); 514 am_hal_stimer_counter_clear(); 515 516 // start with BTstack init - especially configure HCI Transport 517 btstack_memory_init(); 518 btstack_run_loop_init(btstack_run_loop_embedded_get_instance()); 519 520 // init HCI 521 hci_init(hci_transport_em9304_spi_instance(btstack_em9304_spi_embedded_instance()), NULL); 522 // hci_dump_init(hci_dump_embedded_stdout_get_instance()); 523 524 // inform about BTstack state 525 hci_event_callback_registration.callback = &packet_handler; 526 hci_add_event_handler(&hci_event_callback_registration); 527 528 // hand over control to btstack_main().. 529 530 // turn on! 531 // hci_power_control(HCI_POWER_ON); 532 btstack_main(0, NULL); 533 534 btstack_run_loop_execute(); 535 } 536