btstack/port/samv71-xplained-atwilc3000/main.c
2017-08-08 10:56:22 +02:00

539 lines
15 KiB
C

/**
* \file
*
* \brief Getting Started Application.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* \mainpage Getting Started Application
*
* \section Purpose
*
* BTstack port for SAM MCUs
*
* \section Requirements
*
* This package can be used with SAM evaluation kits.
*
* \section Description
*
*
* \section Usage
*
* -# Build the program and download it inside the evaluation board.
* -# On the computer, open and configure a terminal application
* (e.g. HyperTerminal on Microsoft Windows) with these settings:
* - 115200 bauds
* - 8 bits of data
* - No parity
* - 1 stop bit
* - No flow control
* -# Start the application.
*
*/
#include "asf.h"
#include "stdio_serial.h"
#include "conf_board.h"
#include "conf_clock.h"
// BTstack
#include "btstack_run_loop.h"
#include "btstack_run_loop_embedded.h"
#include "btstack_debug.h"
#include "hci.h"
#include "hci_dump.h"
#include "btstack_chipset_atwilc3000.h"
#include "btstack_memory.h"
#include "classic/btstack_link_key_db.h"
#include "hal_uart_dma.h"
#include "hal_cpu.h"
#include "hal_tick.h"
extern int btstack_main(int argc, const char * argv[]);
#define USE_XDMAC_FOR_USART
#define XDMA_CH_UART_TX 0
#define XDMA_CH_UART_RX 1
#define STRING_EOL "\r"
#define STRING_HEADER "-- Getting Started Example --\r\n" \
"-- "BOARD_NAME" --\r\n" \
"-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL
/** All interrupt mask. */
#define ALL_INTERRUPT_MASK 0xffffffff
static void dummy_handler(void){}
static void (*tick_handler)(void) = &dummy_handler;
/** when porting to different setup, please
* disable baudrate change (use 0 instead of 4000000)
* and don't enable eHCILL mode (comment line below)
*/
// after HCI Reset, use 115200. Then increase baud rate to X.
static hci_transport_config_uart_t hci_transport_config = {
HCI_TRANSPORT_CONFIG_UART,
115200,
4000000, // use 0 to skip baud rate change from 115200 to X for debugging purposes
1, // flow control
NULL,
};
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \brief Handler for System Tick interrupt.
*/
void SysTick_Handler(void)
{
tick_handler();
}
/**
* Configure UART console.
*/
// [main_console_configure]
static void configure_console(void)
{
const usart_serial_options_t uart_serial_options = {
.baudrate = CONF_UART_BAUDRATE,
#ifdef CONF_UART_CHAR_LENGTH
.charlength = CONF_UART_CHAR_LENGTH,
#endif
.paritytype = CONF_UART_PARITY,
#ifdef CONF_UART_STOP_BITS
.stopbits = CONF_UART_STOP_BITS,
#endif
};
/* Configure console UART. */
sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
stdio_serial_init(CONF_UART, &uart_serial_options);
}
// [main_console_configure]
/**
* \brief Wait for the given number of milliseconds (ticks
* generated by the SAM's microcontrollers's system tick).
*
* \param ul_dly_ticks Delay to wait for, in milliseconds.
*/
// [main_ms_delay]
static void mdelay(uint32_t delay_in_ms)
{
// delay_ms(delay_in_ms);
uint32_t time_to_wait = btstack_run_loop_get_time_ms() + delay_in_ms;
while (btstack_run_loop_get_time_ms() < time_to_wait);
}
// [main_ms_delay]
////////////////////////////////////////////////////////////////////////////////
// hal_cpu.h implementation
////////////////////////////////////////////////////////////////////////////////
// hal_led.h implementation
#include "hal_led.h"
void hal_led_off(void);
void hal_led_on(void);
void hal_led_off(void){
// gpio_set_pin_low(GPIOA, GPIO_LED2);
}
void hal_led_on(void){
// gpio_set_pin_high(GPIOA, GPIO_LED2);
}
void hal_led_toggle(void){
// gpio_toggle_pin(GPIOA, GPIO_LED2);
}
// hal_cpu.h implementation
#include "hal_cpu.h"
void hal_cpu_disable_irqs(void){
//__disable_irq();
}
void hal_cpu_enable_irqs(void){
// __enable_irq();
}
void hal_cpu_enable_irqs_and_sleep(void){
hal_led_off();
// __enable_irq();
// __asm__("wfe"); // go to sleep if event flag isn't set. if set, just clear it. IRQs set event flag
// note: hal_uart_needed_during_sleep can be used to disable peripheral clock if it's not needed for a timer
hal_led_on();
}
#ifndef USE_XDMAC_FOR_USART
// RX state
static volatile uint16_t bytes_to_read = 0;
static volatile uint8_t * rx_buffer_ptr = 0;
// TX state
static volatile uint16_t bytes_to_write = 0;
static volatile uint8_t * tx_buffer_ptr = 0;
#endif
// handlers
static void (*rx_done_handler)(void) = dummy_handler;
static void (*tx_done_handler)(void) = dummy_handler;
static void (*cts_irq_handler)(void) = dummy_handler;
// @note While the Atmel SAM S7x data sheet states
// "The hardware handshaking feature enables an out-of-band flow control by automatic management
// of the pins RTS and CTS.",
// I didn't see RTS going up automatically up, ever. So, at least for RTS, the automatic management
// is just a glorified GPIO pin control feature, which provides no benefit, but irritates a lot
static void hal_uart_rts_high(void){
BOARD_USART->US_CR = US_CR_RTSEN;
}
static void hal_uart_rts_low(void){
BOARD_USART->US_CR = US_CR_RTSDIS;
}
/**
*/
void hal_uart_dma_init(void)
{
// configure n_shutdown pin, and reset Bluetooth
ioport_set_pin_dir(N_SHUTDOWN, IOPORT_DIR_OUTPUT);
ioport_set_pin_level(N_SHUTDOWN, IOPORT_PIN_LEVEL_LOW);
mdelay(100);
ioport_set_pin_level(N_SHUTDOWN, IOPORT_PIN_LEVEL_HIGH);
mdelay(500);
// configure Bluetooth USART
const sam_usart_opt_t bluetooth_settings = {
115200,
US_MR_CHRL_8_BIT,
US_MR_PAR_NO,
US_MR_NBSTOP_1_BIT,
US_MR_CHMODE_NORMAL,
/* This field is only used in IrDA mode. */
0
};
/* Enable the peripheral clock in the PMC. */
sysclk_enable_peripheral_clock(BOARD_ID_USART);
/* Configure USART mode. */
usart_init_hw_handshaking(BOARD_USART, &bluetooth_settings, sysclk_get_peripheral_hz());
/* Disable all the interrupts. */
usart_disable_interrupt(BOARD_USART, ALL_INTERRUPT_MASK);
// RX not ready yet
// usart_drive_RTS_pin_high(BOARD_USART);
/* Enable TX & RX function. */
usart_enable_tx(BOARD_USART);
usart_enable_rx(BOARD_USART);
/* Configure and enable interrupt of USART. */
NVIC_EnableIRQ(USART_IRQn);
#ifdef USE_XDMAC_FOR_USART
// setup XDMAC
/* Initialize and enable DMA controller */
pmc_enable_periph_clk(ID_XDMAC);
/* Enable XDMA interrupt */
NVIC_ClearPendingIRQ(XDMAC_IRQn);
NVIC_SetPriority( XDMAC_IRQn ,1);
NVIC_EnableIRQ(XDMAC_IRQn);
// Setup XDMA Channel for USART TX
xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)&BOARD_USART->US_THR);
xdmac_channel_set_config(XDMAC, XDMA_CH_UART_TX,
XDMAC_CC_TYPE_PER_TRAN |
XDMAC_CC_DSYNC_MEM2PER |
XDMAC_CC_MEMSET_NORMAL_MODE |
XDMAC_CC_MBSIZE_SINGLE |
XDMAC_CC_DWIDTH_BYTE |
XDMAC_CC_SIF_AHB_IF0 |
XDMAC_CC_DIF_AHB_IF1 |
XDMAC_CC_SAM_INCREMENTED_AM |
XDMAC_CC_DAM_FIXED_AM |
XDMAC_CC_CSIZE_CHK_1 |
XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_TX)
);
xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_TX, 0);
xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0);
xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_TX, 0);
xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_TX, 0);
xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_TX, 0);
xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_TX);
xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_TX, XDMAC_CIE_BIE);
// Setup XDMA Channel for USART RX
xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)&BOARD_USART->US_RHR);
xdmac_channel_set_config(XDMAC, XDMA_CH_UART_RX,
XDMAC_CC_TYPE_PER_TRAN |
XDMAC_CC_DSYNC_PER2MEM |
XDMAC_CC_MEMSET_NORMAL_MODE |
XDMAC_CC_MBSIZE_SINGLE |
XDMAC_CC_DWIDTH_BYTE |
XDMAC_CC_SIF_AHB_IF1 |
XDMAC_CC_DIF_AHB_IF0 |
XDMAC_CC_SAM_FIXED_AM |
XDMAC_CC_DAM_INCREMENTED_AM |
XDMAC_CC_CSIZE_CHK_1 |
XDMAC_CC_PERID(XDAMC_CHANNEL_HWID_USART0_RX)
);
xdmac_channel_set_descriptor_control(XDMAC, XDMA_CH_UART_RX, 0);
xdmac_channel_set_source_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0);
xdmac_channel_set_destination_microblock_stride(XDMAC, XDMA_CH_UART_RX, 0);
xdmac_channel_set_datastride_mempattern(XDMAC, XDMA_CH_UART_RX, 0);
xdmac_channel_set_block_control(XDMAC, XDMA_CH_UART_RX, 0);
xdmac_enable_interrupt(XDMAC, XDMA_CH_UART_RX);
xdmac_channel_enable_interrupt(XDMAC, XDMA_CH_UART_RX, XDMAC_CIE_BIE);
#endif
}
void hal_uart_dma_set_sleep(uint8_t sleep){
}
void hal_uart_dma_set_block_received( void (*the_block_handler)(void)){
rx_done_handler = the_block_handler;
}
void hal_uart_dma_set_block_sent( void (*the_block_handler)(void)){
tx_done_handler = the_block_handler;
}
void hal_uart_dma_set_csr_irq_handler( void (*the_irq_handler)(void)){
cts_irq_handler = the_irq_handler;
}
int hal_uart_dma_set_baud(uint32_t baud){
/* Disable TX & RX function. */
usart_disable_tx(BOARD_USART);
usart_disable_rx(BOARD_USART);
uint32_t res = usart_set_async_baudrate(BOARD_USART, baud, sysclk_get_peripheral_hz());
if (res){
log_error("hal_uart_dma_set_baud library call failed");
}
/* Enable TX & RX function. */
usart_enable_tx(BOARD_USART);
usart_enable_rx(BOARD_USART);
log_info("Bump baud rate");
return 0;
}
void hal_uart_dma_send_block(const uint8_t *data, uint16_t size){
#ifdef USE_XDMAC_FOR_USART
xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_TX);
xdmac_channel_set_source_addr(XDMAC, XDMA_CH_UART_TX, (uint32_t)data);
xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_TX, size);
xdmac_channel_enable(XDMAC, XDMA_CH_UART_TX);
#else
tx_buffer_ptr = (uint8_t *) data;
bytes_to_write = size;
usart_enable_interrupt(BOARD_USART, US_IER_TXRDY);
#endif
}
void hal_uart_dma_receive_block(uint8_t *data, uint16_t size){
hal_uart_rts_low();
#ifdef USE_XDMAC_FOR_USART
xdmac_channel_get_interrupt_status( XDMAC, XDMA_CH_UART_RX);
xdmac_channel_set_destination_addr(XDMAC, XDMA_CH_UART_RX, (uint32_t)data);
xdmac_channel_set_microblock_control(XDMAC, XDMA_CH_UART_RX, size);
xdmac_channel_enable(XDMAC, XDMA_CH_UART_RX);
#else
rx_buffer_ptr = data;
bytes_to_read = size;
usart_enable_interrupt(BOARD_USART, US_IER_RXRDY);
#endif
}
#ifdef USE_XDMAC_FOR_USART
void XDMAC_Handler(void)
{
uint32_t dma_status;
dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_TX);
if (dma_status & XDMAC_CIS_BIS) {
tx_done_handler();
}
dma_status = xdmac_channel_get_interrupt_status(XDMAC, XDMA_CH_UART_RX);
if (dma_status & XDMAC_CIS_BIS) {
hal_uart_rts_high();
rx_done_handler();
}
}
#else
void USART_Handler(void)
{
uint32_t ul_status;
uint8_t uc_char;
/* Read USART status. */
ul_status = usart_get_status(BOARD_USART);
// handle ready to send
if(ul_status & US_IER_TXRDY) {
if (bytes_to_write){
// send next byte
usart_write(BOARD_USART, *tx_buffer_ptr);
tx_buffer_ptr++;
bytes_to_write--;
} else {
// done. disable tx ready interrupt to avoid starvation here
usart_disable_interrupt(BOARD_USART, US_IER_TXRDY);
tx_done_handler();
}
}
// handle byte available for read
if (ul_status & US_IER_RXRDY) {
uint32_t ch;
usart_read(BOARD_USART, (uint32_t *)&ch);
*rx_buffer_ptr++ = ch;
bytes_to_read--;
if (bytes_to_read == 0){
// done. disable rx ready interrupt, raise RTS
hal_uart_rts_high();
usart_disable_interrupt(BOARD_USART, US_IER_RXRDY);
rx_done_handler();
}
}
}
#endif
void hal_tick_init()
{
/* Configure systick for 1 ms */
puts("Configure system tick to get 1ms tick period.\r");
if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
puts("-F- Systick configuration error\r");
while (1);
}
}
void hal_tick_set_handler(void (*handler)(void)){
if (handler == NULL){
tick_handler = &dummy_handler;
return;
}
tick_handler = handler;
}
int hal_tick_get_tick_period_in_ms(void){
return 1;
}
/**
* \brief getting-started Application entry point.
*
* \return Unused (ANSI-C compatibility).
*/
// [main]
int main(void)
{
//! [main_step_sys_init]
/* Initialize the SAM system */
sysclk_init();
board_init();
//! [main_step_sys_init]
//! [main_step_console_init]
/* Initialize the console uart */
configure_console();
//! [main_step_console_init]
/* Output example information */
puts(STRING_HEADER);
printf("CPU %lu hz, peripheral clock %lu hz\n", sysclk_get_cpu_hz(), sysclk_get_peripheral_hz());
// start with BTstack init - especially configure HCI Transport
btstack_memory_init();
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
// enable full log output while porting
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
// init HCI
// hci_init(hci_transport_h4_instance(), (void*) &hci_transport_config);
// hci_set_chipset(btstack_chipset_cc256x_instance());
// hci_set_link_key_db(btstack_link_key_db_memory_instance());
// enable eHCILL
// bt_control_cc256x_enable_ehcill(1);
// hand over to btstack embedded code
btstack_main(0, NULL);
// go
btstack_run_loop_execute();
// compiler happy
while(1);
}
// [main]
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond