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
uart_init(uint32_t ui32Module)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
uart_disable(uint32_t ui32Module)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
am_devices_em9304_spi_init(uint32_t ui32Module,const am_hal_iom_config_t * psIomConfig)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
configure_em9304_pins(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
em9304_init(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
hal_cpu_disable_irqs(void)210 void hal_cpu_disable_irqs(void){
211 am_hal_interrupt_master_disable();
212 }
213
hal_cpu_enable_irqs(void)214 void hal_cpu_enable_irqs(void){
215 am_hal_interrupt_master_enable();
216 }
217
hal_cpu_enable_irqs_and_sleep(void)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"
hal_time_ms(void)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);
_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 }
_read(int file,char * ptr,int len)263 int _read(int file, char * ptr, int len){
264 (void)file;
265 (void)ptr;
266 (void)len;
267 return -1;
268 }
269
_close(int file)270 int _close(int file){
271 (void)file;
272 return -1;
273 }
274
_isatty(int file)275 int _isatty(int file){
276 (void)file;
277 return -1;
278 }
279
_lseek(int file)280 int _lseek(int file){
281 (void)file;
282 return -1;
283 }
284
_fstat(int file)285 int _fstat(int file){
286 (void)file;
287 return -1;
288 }
289
_sbrk(intptr_t increment)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
am_iomaster0_isr(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
am_iomaster5_isr(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
am_gpio_isr(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
hal_em9304_spi_enable_ready_interrupt(void)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
hal_em9304_spi_disable_ready_interrupt(void)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
hal_em9304_spi_set_ready_callback(void (* done)(void))373 void hal_em9304_spi_set_ready_callback(void (*done)(void)){
374 hal_em9304_spi_ready_callback = done;
375 }
376
hal_em9304_spi_get_ready(void)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
hal_em9304_spi_init(void)381 void hal_em9304_spi_init(void){
382 hal_em9304_spi_disable_ready_interrupt();
383 }
384
hal_em9304_spi_deinit(void)385 void hal_em9304_spi_deinit(void){
386 hal_em9304_spi_disable_ready_interrupt();
387 }
388
hal_em9304_spi_set_transfer_done_callback(void (* done)(void))389 void hal_em9304_spi_set_transfer_done_callback(void (*done)(void)){
390 hal_em9304_spi_transfer_done_callback = done;
391 }
392
hal_em9304_spi_set_chip_select(int enable)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
hal_em9304_spi_transceive(const uint8_t * tx_data,uint8_t * rx_data,uint16_t len)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
hal_em9304_spi_transmit(const uint8_t * tx_data,uint16_t len)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
hal_em9304_spi_receive(uint8_t * rx_data,uint16_t len)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
hal_em9304_spi_get_fullduplex_support(void)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 #include "hci_transport.h"
448 #include "hci_transport_em9304_spi.h"
449
450 static btstack_packet_callback_registration_t hci_event_callback_registration;
451 int btstack_main(int argc, char ** argv);
452
453 // main.c
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)454 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
455 UNUSED(size);
456 UNUSED(channel);
457 if (packet_type != HCI_EVENT_PACKET) return;
458 switch(hci_event_packet_get_type(packet)){
459 case BTSTACK_EVENT_STATE:
460 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
461 printf("BTstack up and running.\n");
462 break;
463 default:
464 break;
465 }
466 }
467
main(void)468 int main(void)
469 {
470 //
471 // Set the clock frequency.
472 //
473 am_hal_clkgen_sysclk_select(AM_HAL_CLKGEN_SYSCLK_MAX);
474
475 //
476 // Set the default cache configuration
477 //
478 am_hal_cachectrl_enable(&am_hal_cachectrl_defaults);
479
480 //
481 // Configure the board for low power operation.
482 //
483 am_bsp_low_power_init();
484
485 //
486 // Initialize the printf interface for UART output.
487 //
488 am_util_stdio_printf_init((am_util_stdio_print_char_t)am_bsp_uart_string_print);
489
490 //
491 // Configure and enable the UART.
492 //
493 uart_init(AM_BSP_UART_PRINT_INST);
494
495 //
496 // Reboot and configure em9304.
497 //
498 em9304_init();
499
500 am_hal_interrupt_enable(AM_HAL_INTERRUPT_GPIO);
501
502 //
503 // Enable IOM SPI interrupts.
504 //
505 am_hal_iom_int_clear(AM_BSP_EM9304_IOM, AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_THR);
506 am_hal_iom_int_enable(AM_BSP_EM9304_IOM, AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_THR);
507
508 #if (0 == AM_BSP_EM9304_IOM)
509 am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOMASTER0);
510 #elif (5 == AM_BSP_EM9304_IOM)
511 am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOMASTER5);
512 #endif
513
514 // Start System Timer (only Apollo 2)
515 am_hal_stimer_config(AM_HAL_STIMER_LFRC_1KHZ);
516 am_hal_stimer_counter_clear();
517
518 // start with BTstack init - especially configure HCI Transport
519 btstack_memory_init();
520 btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
521
522 // init HCI
523 hci_init(hci_transport_em9304_spi_instance(btstack_em9304_spi_embedded_instance()), NULL);
524 // hci_dump_init(hci_dump_embedded_stdout_get_instance());
525
526 // inform about BTstack state
527 hci_event_callback_registration.callback = &packet_handler;
528 hci_add_event_handler(&hci_event_callback_registration);
529
530 // hand over control to btstack_main()..
531
532 // turn on!
533 // hci_power_control(HCI_POWER_ON);
534 btstack_main(0, NULL);
535
536 btstack_run_loop_execute();
537 }
538