mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-03 23:47:08 +00:00
535 lines
13 KiB
C
535 lines
13 KiB
C
//
|
|
// 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_stimer_counter_get();
|
|
}
|
|
|
|
|
|
/**
|
|
* Use USART_CONSOLE as a console.
|
|
* This is a syscall for newlib
|
|
* @param file
|
|
* @param ptr
|
|
* @param len
|
|
* @return
|
|
*/
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
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_event.h"
|
|
#include "btstack_memory.h"
|
|
#include "btstack_run_loop.h"
|
|
#include "btstack_run_loop_embedded.h"
|
|
#include "hci_dump.h"
|
|
|
|
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
|
int btstack_main(int argc, char ** argv);
|
|
|
|
// main.c
|
|
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
|
UNUSED(size);
|
|
UNUSED(channel);
|
|
if (packet_type != HCI_EVENT_PACKET) return;
|
|
switch(hci_event_packet_get_type(packet)){
|
|
case BTSTACK_EVENT_STATE:
|
|
if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) return;
|
|
printf("BTstack up and running.\n");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
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 System Timer (only Apollo 2)
|
|
am_hal_stimer_config(AM_HAL_STIMER_LFRC_1KHZ);
|
|
am_hal_stimer_counter_clear();
|
|
|
|
// 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 );
|
|
|
|
// inform about BTstack state
|
|
hci_event_callback_registration.callback = &packet_handler;
|
|
hci_add_event_handler(&hci_event_callback_registration);
|
|
|
|
// hand over control to btstack_main()..
|
|
|
|
// turn on!
|
|
// hci_power_control(HCI_POWER_ON);
|
|
btstack_main(0, NULL);
|
|
|
|
btstack_run_loop_execute();
|
|
}
|