xref: /btstack/port/apollo2-em9304/btstack_port.c (revision c8dfe071e5be306bdac290dfbe6cbf2b9a446e88)
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