From 905e80ca54f367b5f3231ecddf9a2dcb3fca37a4 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 19 Dec 2017 23:21:14 +0100 Subject: [PATCH] apollo2-em9304: port for em9304 shield on apollo2 evb --- port/apollo2-em9304/btstack_config.h | 38 ++ port/apollo2-em9304/btstack_port.c | 508 +++++++++++++++++++++++++++ 2 files changed, 546 insertions(+) create mode 100644 port/apollo2-em9304/btstack_config.h create mode 100644 port/apollo2-em9304/btstack_port.c diff --git a/port/apollo2-em9304/btstack_config.h b/port/apollo2-em9304/btstack_config.h new file mode 100644 index 000000000..20183e14d --- /dev/null +++ b/port/apollo2-em9304/btstack_config.h @@ -0,0 +1,38 @@ +// +// btstack_config.h for EM9304 DVK +// + +#ifndef __BTSTACK_CONFIG +#define __BTSTACK_CONFIG + +// Port related features +#define HAVE_EMBEDDED_TIME_MS + +// BTstack features that can be enabled +#define ENABLE_BLE +#define ENABLE_LE_PERIPHERAL +#define ENABLE_LE_CENTRAL +#define ENABLE_LE_DATA_LENGTH_EXTENSION +#define ENABLE_LOG_INFO +#define ENABLE_LOG_ERROR + +// BTstack configuration. buffers, sizes, ... +#define HCI_ACL_PAYLOAD_SIZE 100 +#define MAX_NR_WHITELIST_ENTRIES 1 +#define MAX_NR_HCI_CONNECTIONS 1 +#define MAX_NR_SM_LOOKUP_ENTRIES 3 +#define MAX_NR_L2CAP_SERVICES 1 +#define MAX_NR_L2CAP_CHANNELS 1 +#define MAX_NR_GATT_CLIENTS 1 + +#define MAX_NR_RFCOMM_MULTIPLEXERS 0 +#define MAX_NR_RFCOMM_SERVICES 0 +#define MAX_NR_RFCOMM_CHANNELS 0 +#define MAX_NR_HFP_CONNECTIONS 0 +#define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 0 +#define MAX_NR_BNEP_SERVICES 0 +#define MAX_NR_BNEP_CHANNELS 0 +#define MAX_NR_SERVICE_RECORD_ITEMS 1 +#define MAX_NR_LE_DEVICE_DB_ENTRIES 1 + +#endif \ No newline at end of file diff --git a/port/apollo2-em9304/btstack_port.c b/port/apollo2-em9304/btstack_port.c new file mode 100644 index 000000000..678a50d96 --- /dev/null +++ b/port/apollo2-em9304/btstack_port.c @@ -0,0 +1,508 @@ +// +// BTstack port for Apolle 2 EVB with EM9304 shield +// + +#include "am_mcu_apollo.h" +#include "am_bsp.h" +#include "am_util.h" +#include "am_devices_em9304.h" + +//***************************************************************************** +// +// Insert compiler version at compile time. +// +//***************************************************************************** +#define STRINGIZE_VAL(n) STRINGIZE_VAL2(n) +#define STRINGIZE_VAL2(n) #n + +#ifdef __GNUC__ +#define COMPILER_VERSION ("GCC " __VERSION__) +#elif defined(__ARMCC_VERSION) +#define COMPILER_VERSION ("ARMCC " STRINGIZE_VAL(__ARMCC_VERSION)) +#elif defined(__KEIL__) +#define COMPILER_VERSION "KEIL_CARM " STRINGIZE_VAL(__CA__) +#elif defined(__IAR_SYSTEMS_ICC__) +#define COMPILER_VERSION __VERSION__ +#else +#define COMPILER_VERSION "Compiler unknown" +#endif + +//***************************************************************************** +// +// IOM SPI Configuration for EM9304 +// +//***************************************************************************** +const am_hal_iom_config_t g_sEm9304IOMConfigSPI = +{ + .ui32ClockFrequency = AM_HAL_IOM_8MHZ, + .ui32InterfaceMode = AM_HAL_IOM_SPIMODE, + .ui8WriteThreshold = 20, + .ui8ReadThreshold = 20, + .bSPHA = 0, + .bSPOL = 0, +}; + +//***************************************************************************** +// +// UART configuration settings. +// +//***************************************************************************** +am_hal_uart_config_t g_sUartConfig = +{ + .ui32BaudRate = 115200, + .ui32DataBits = AM_HAL_UART_DATA_BITS_8, + .bTwoStopBits = false, + .ui32Parity = AM_HAL_UART_PARITY_NONE, + .ui32FlowCtrl = AM_HAL_UART_FLOW_CTRL_NONE, +}; + +//***************************************************************************** +// +// Initialize the UART +// +//***************************************************************************** +void +uart_init(uint32_t ui32Module) +{ + // + // Make sure the UART RX and TX pins are enabled. + // + am_bsp_pin_enable(COM_UART_TX); + am_bsp_pin_enable(COM_UART_RX); + + // + // Power on the selected UART + // + am_hal_uart_pwrctrl_enable(ui32Module); + + // + // Start the UART interface, apply the desired configuration settings, and + // enable the FIFOs. + // + am_hal_uart_clock_enable(ui32Module); + + // + // Disable the UART before configuring it. + // + am_hal_uart_disable(ui32Module); + + // + // Configure the UART. + // + am_hal_uart_config(ui32Module, &g_sUartConfig); + + // + // Enable the UART FIFO. + // + am_hal_uart_fifo_config(ui32Module, AM_HAL_UART_TX_FIFO_1_2 | AM_HAL_UART_RX_FIFO_1_2); + + // + // Enable the UART. + // + am_hal_uart_enable(ui32Module); +} + +//***************************************************************************** +// +// Disable the UART +// +//***************************************************************************** +void +uart_disable(uint32_t ui32Module) +{ + // + // Clear all interrupts before sleeping as having a pending UART interrupt + // burns power. + // + am_hal_uart_int_clear(ui32Module, 0xFFFFFFFF); + + // + // Disable the UART. + // + am_hal_uart_disable(ui32Module); + + // + // Disable the UART pins. + // + am_bsp_pin_disable(COM_UART_TX); + am_bsp_pin_disable(COM_UART_RX); + + // + // Disable the UART clock. + // + am_hal_uart_clock_disable(ui32Module); +} + +//***************************************************************************** +// +// Initialize the EM9304 BLE Controller +// +//***************************************************************************** +void +am_devices_em9304_spi_init(uint32_t ui32Module, const am_hal_iom_config_t *psIomConfig) +{ + if ( AM_REGn(IOMSTR, ui32Module, CFG) & AM_REG_IOMSTR_CFG_IFCEN_M ) + { + return; + } + +#if defined(AM_PART_APOLLO2) + am_hal_iom_pwrctrl_enable(ui32Module); +#endif + // + // Setup the pins for SPI mode. + // + am_bsp_iom_spi_pins_enable(ui32Module); + + // + // Set the required configuration settings for the IOM. + // + am_hal_iom_config(ui32Module, psIomConfig); + + // Enable spi + am_hal_iom_enable(ui32Module); +} + +void +configure_em9304_pins(void) +{ + am_bsp_pin_enable(EM9304_CS); + am_bsp_pin_enable(EM9304_INT); + + am_hal_gpio_out_bit_set(AM_BSP_GPIO_EM9304_CS); + + am_hal_gpio_int_polarity_bit_set(AM_BSP_GPIO_EM9304_INT, AM_HAL_GPIO_RISING); + am_hal_gpio_int_clear(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); + am_hal_gpio_int_enable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); +} + +void +em9304_init(void) +{ + // + // Assert RESET to the Telink device. + // + am_hal_gpio_pin_config(AM_BSP_GPIO_EM9304_RESET, AM_HAL_GPIO_OUTPUT); + am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_RESET); + + // + // Setup SPI interface for EM9304 + // + configure_em9304_pins(); + am_devices_em9304_spi_init(AM_BSP_EM9304_IOM, &g_sEm9304IOMConfigSPI); + + // + // Delay for 20ms to make sure the em device gets ready for commands. + // + am_util_delay_ms(5); + + // + // Enable the IOM and GPIO interrupt handlers. + // + am_hal_gpio_out_bit_set(AM_BSP_GPIO_EM9304_RESET); + + am_util_delay_ms(20); +} + +// hal_cpu.h implementation +#include "hal_cpu.h" + +void hal_cpu_disable_irqs(void){ + am_hal_interrupt_master_disable(); +} + +void hal_cpu_enable_irqs(void){ + am_hal_interrupt_master_enable(); +} + +void hal_cpu_enable_irqs_and_sleep(void){ + am_hal_interrupt_master_enable(); + __asm__("wfe"); // go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag +} + + +// hal_time_ms.h +#include "hal_time_ms.h" +uint32_t hal_time_ms(void){ + return am_hal_systick_count(); +} + + +/** + * Use USART_CONSOLE as a console. + * This is a syscall for newlib + * @param file + * @param ptr + * @param len + * @return + */ +#include +#include +#include +int _write(int file, char *ptr, int len); +int _write(int file, char *ptr, int len){ +#if 1 + uint8_t cr = '\r'; + int i; + + if (file == STDOUT_FILENO || file == STDERR_FILENO) { + for (i = 0; i < len; i++) { + if (ptr[i] == '\n') { + am_hal_uart_char_transmit_polled( AM_BSP_UART_PRINT_INST, cr ); + } + am_hal_uart_char_transmit_polled( AM_BSP_UART_PRINT_INST, ptr[i]); +} +return i; +} +errno = EIO; +return -1; +#else + return len; +#endif +} +int _read(int file, char * ptr, int len){ + (void)file; + (void)ptr; + (void)len; + return -1; +} + +int _close(int file){ + (void)file; + return -1; +} + +int _isatty(int file){ + (void)file; + return -1; +} + +int _lseek(int file){ + (void)file; + return -1; +} + +int _fstat(int file){ + (void)file; + return -1; +} + +void * _sbrk(intptr_t increment){ + return (void*) -1; +} + + +// hal_em9304_spi.h +#include "hal_em9304_spi.h" + +static void (*hal_em9304_spi_transfer_done_callback)(void); +static void (*hal_em9304_spi_ready_callback)(void); + +#if (0 == AM_BSP_EM9304_IOM) +void +am_iomaster0_isr(void) +{ + uint32_t ui32IntStatus; + + // + // Read and clear the interrupt status. + // + ui32IntStatus = am_hal_iom_int_status_get(0, false); + am_hal_iom_int_clear(0, ui32IntStatus); + + // + // Service FIFO interrupts as necessary, and call IOM callbacks as + // transfers are completed. + // + am_hal_iom_int_service(0, ui32IntStatus); +} +#endif + +#if defined(AM_PART_APOLLO2) +#if (5 == AM_BSP_EM9304_IOM) +void +am_iomaster5_isr(void) +{ + uint32_t ui32IntStatus; + + // + // Read and clear the interrupt status. + // + ui32IntStatus = am_hal_iom_int_status_get(5, false); + am_hal_iom_int_clear(5, ui32IntStatus); + + // + // Service FIFO interrupts as necessary, and call IOM callbacks as + // transfers are completed. + // + am_hal_iom_int_service(5, ui32IntStatus); +} +#endif +#endif + +void +am_gpio_isr(void) +{ + uint64_t ui64Status; + + // + // Check and clear the GPIO interrupt status + // + ui64Status = am_hal_gpio_int_status_get(true); + am_hal_gpio_int_clear(ui64Status); + + // + // Check to see if this was a wakeup event from the BLE radio. + // + if ( ui64Status & AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT) ) + { + if (hal_em9304_spi_ready_callback){ + (*hal_em9304_spi_ready_callback)(); + } + } +} + +void hal_em9304_spi_enable_ready_interrupt(void){ + am_hal_gpio_int_enable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); +} + +void hal_em9304_spi_disable_ready_interrupt(void){ + am_hal_gpio_int_disable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT)); +} + +void hal_em9304_spi_set_ready_callback(void (*done)(void)){ + hal_em9304_spi_ready_callback = done; +} + +int hal_em9304_spi_get_ready(void){ + return am_hal_gpio_input_read() & AM_HAL_GPIO_BIT(AM_BSP_GPIO_EM9304_INT); +} + +void hal_em9304_spi_init(void){ + hal_em9304_spi_disable_ready_interrupt(); +} + +void hal_em9304_spi_deinit(void){ + hal_em9304_spi_disable_ready_interrupt(); +} + +void hal_em9304_spi_set_transfer_done_callback(void (*done)(void)){ + hal_em9304_spi_transfer_done_callback = done; +} + +void hal_em9304_spi_set_chip_select(int enable){ + if (enable){ + am_hal_gpio_out_bit_clear(AM_BSP_GPIO_EM9304_CS); + } else { + am_hal_gpio_out_bit_set(AM_BSP_GPIO_EM9304_CS); + } +} + +void hal_em9304_spi_transceive(const uint8_t * tx_data, uint8_t * rx_data, uint16_t len){ + // TODO: handle tx_data/rx_data not aligned + // TODO: support non-blocking full duplex + uint32_t ui32ChipSelect = 0; + // TODO: Use Full Duplex with Interrupt callback + // NOTE: Full Duplex only supported on Apollo2 + // NOTE: Enabling Full Duplex causes am_hal_iom_spi_write_nq to block (as bytes ready returns number of bytes written) + // AM_REGn(IOMSTR, ui32Module, CFG) |= AM_REG_IOMSTR_CFG_FULLDUP(1); + am_hal_iom_spi_fullduplex_nq(AM_BSP_EM9304_IOM, ui32ChipSelect, (uint32_t *) tx_data, (uint32_t *) rx_data, len, AM_HAL_IOM_RAW); + (*hal_em9304_spi_transfer_done_callback)(); + return; +} + +void hal_em9304_spi_transmit(const uint8_t * tx_data, uint16_t len){ + // TODO: handle tx_data/rx_data not aligned + uint32_t ui32ChipSelect = 0; + 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); +} + +void hal_em9304_spi_receive(uint8_t * rx_data, uint16_t len){ + // TODO: handle tx_data/rx_data not aligned + // TODO: support non-blocking full duplex + uint32_t ui32ChipSelect = 0; + 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); +} + +int hal_em9304_spi_get_fullduplex_support(void){ + return 0; +} + +//***************************************************************************** +// +// Main +// +//***************************************************************************** + + +// EM 9304 SPI Master HCI Implementation +const uint8_t hci_reset_2[] = { 0x01, 0x03, 0x0c, 0x00 }; + +#include "btstack_run_loop.h" +#include "btstack_run_loop_embedded.h" +#include "btstack_memory.h" +#include "hci_dump.h" + +int btstack_main(int argc, const char * argv[]); +int main(void) +{ + // + // Set the clock frequency. + // + am_hal_clkgen_sysclk_select(AM_HAL_CLKGEN_SYSCLK_MAX); + + // + // Set the default cache configuration + // + am_hal_cachectrl_enable(&am_hal_cachectrl_defaults); + + // + // Configure the board for low power operation. + // + am_bsp_low_power_init(); + + // + // Initialize the printf interface for UART output. + // + am_util_stdio_printf_init((am_util_stdio_print_char_t)am_bsp_uart_string_print); + + // + // Configure and enable the UART. + // + uart_init(AM_BSP_UART_PRINT_INST); + + // + // Reboot and configure em9304. + // + em9304_init(); + + am_hal_interrupt_enable(AM_HAL_INTERRUPT_GPIO); + + // + // Enable IOM SPI interrupts. + // + am_hal_iom_int_clear(AM_BSP_EM9304_IOM, AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_THR); + am_hal_iom_int_enable(AM_BSP_EM9304_IOM, AM_HAL_IOM_INT_CMDCMP | AM_HAL_IOM_INT_THR); + +#if (0 == AM_BSP_EM9304_IOM) + am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOMASTER0); +#elif (5 == AM_BSP_EM9304_IOM) + am_hal_interrupt_enable(AM_HAL_INTERRUPT_IOMASTER5); +#endif + + // start with BTstack init - especially configure HCI Transport + btstack_memory_init(); + btstack_run_loop_init(btstack_run_loop_embedded_get_instance()); + + // init HCI + hci_init(hci_transport_em9304_spi_instance(btstack_em9304_spi_embedded_instance()), NULL); + hci_dump_open( NULL, HCI_DUMP_STDOUT ); + + // hand over control to btstack_main().. + + // turn on! + // hci_power_control(HCI_POWER_ON); + btstack_main(0, NULL); + + btstack_run_loop_execute(); +}