initial commit
This commit is contained in:
@@ -0,0 +1,763 @@
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file main.c
|
||||
//!
|
||||
//! @brief A variable-baud rate bootloader for Apollo3 / Artemis module
|
||||
//!
|
||||
//! Purpose:
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
/*
|
||||
Copyright (c) 2020 SparkFun Electronics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Authors:
|
||||
Owen Lyke, Nathan Seidle
|
||||
|
||||
Modified: Juy 22 2019
|
||||
|
||||
*/
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Includes
|
||||
//
|
||||
//*****************************************************************************
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#include "svl_ringbuf.h"
|
||||
#include "svl_packet.h"
|
||||
#include "svl_uart.h"
|
||||
#include "svl_utils.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define SVL_VERSION_NUMBER 0x05
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Bootloader Options
|
||||
//
|
||||
// ****************************************
|
||||
#define BL_UART_BUF_LEN (2048 + 512) // must be larger than maximum frame transmission length for guaranteed performance
|
||||
#define BL_UART_INST 0 // which UART peripheral to use for BL data
|
||||
#define BL_RX_PAD 49 // RX pad for BL_UART_INST
|
||||
#define BL_TX_PAD 48 // TX pad for BL_UART_INST
|
||||
#define USERCODE_OFFSET (0xC000 + 0x4000) // location in flash to begin storing user's code (Linker script needs to be adjusted to offset user's flash to this address)
|
||||
#define FRAME_BUFFER_SIZE 512 // maximum number of 4-byte words that can be transmitted in a single frame packet
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Debug Options
|
||||
//
|
||||
// ****************************************
|
||||
|
||||
//#define DEBUG 1 // uncomment to enable debug output
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_BAUD_RATE 921600 // debug output baud rate
|
||||
#define DEBUG_UART_INST 1 // debug UART peripheral instance (should not be the same as BL_UART_INST)
|
||||
#define DEBUG_RX_PAD 25 // RX pad for
|
||||
#define DEBUG_TX_PAD 24
|
||||
#define DEBUG_UART_BUF_LEN 256
|
||||
#define DEBUG_PRINT_APP 1 // undefine to not print app pages
|
||||
#define APP_PRINT_NUM_PAGE 1
|
||||
#undef APP_PRINT_PRETTY // define APP_PRINT_PRETTY for the alternate app data print format
|
||||
uint8_t debug_buffer[DEBUG_UART_BUF_LEN] = {0};
|
||||
#endif // DEBUG
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Bootloader Commands
|
||||
//
|
||||
// ****************************************
|
||||
#define CMD_VERSION (0x01)
|
||||
#define CMD_BLMODE (0x02)
|
||||
#define CMD_NEXT (0x03)
|
||||
#define CMD_FRAME (0x04)
|
||||
#define CMD_RETRY (0x05)
|
||||
#define CMD_DONE (0x06)
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Macros
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define UART_GPIO_PINCONFIG_INNER(INST, TXRX, PAD) \
|
||||
{ \
|
||||
.uFuncSel = AM_HAL_PIN_##PAD##_UART##INST##TXRX, .eDriveStrength = AM_HAL_GPIO_PIN_DRIVESTRENGTH_2MA \
|
||||
}
|
||||
#define UART_GPIO_PINCONFIG(INST, TXRX, PAD) UART_GPIO_PINCONFIG_INNER(INST, TXRX, PAD)
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Forward Declarations
|
||||
//
|
||||
//*****************************************************************************
|
||||
void setup(void);
|
||||
bool detect_baud_rate(uint32_t *baud);
|
||||
void start_uart_bl(uint32_t baud);
|
||||
void enter_bootload(void);
|
||||
uint8_t handle_frame_packet(svl_packet_t *packet, uint32_t *p_frame_address, uint16_t *p_last_page_erased);
|
||||
void app_start(void);
|
||||
void debug_printf(char *fmt, ...);
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
//*****************************************************************************
|
||||
art_svl_ringbuf_t bl_rx_ringbuf = {
|
||||
.buf = NULL,
|
||||
.len = 0,
|
||||
.r_offset = 0,
|
||||
.w_offset = 0,
|
||||
};
|
||||
void *hUART_bl = NULL; // pointer to handle for bootloader UART
|
||||
void *hUART_debug = NULL; // pointer to handle for debug UART
|
||||
|
||||
#define BL_BAUD_SAMPLES (5)
|
||||
volatile uint8_t bl_baud_ticks_index = 0x00;
|
||||
volatile uint32_t bl_baud_ticks[BL_BAUD_SAMPLES] = {0};
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Main
|
||||
//
|
||||
//*****************************************************************************
|
||||
int main(void)
|
||||
{
|
||||
|
||||
bool baud_valid = false;
|
||||
uint32_t bl_baud = 0x00;
|
||||
uint8_t bl_buffer[BL_UART_BUF_LEN] = {0};
|
||||
|
||||
#define PLLEN_VER 1
|
||||
uint8_t packet_ver_buf[PLLEN_VER] = {SVL_VERSION_NUMBER};
|
||||
svl_packet_t svl_packet_version = {CMD_VERSION, packet_ver_buf, PLLEN_VER, PLLEN_VER};
|
||||
svl_packet_t svl_packet_blmode = {CMD_BLMODE, NULL, 0, 0};
|
||||
|
||||
art_svl_ringbuf_init(&bl_rx_ringbuf, bl_buffer, BL_UART_BUF_LEN);
|
||||
setup();
|
||||
|
||||
debug_printf("\n\nArtemis SVL Bootloader - DEBUG\n\n");
|
||||
|
||||
baud_valid = detect_baud_rate(&bl_baud); // Detects the baud rate. Returns true if a valid baud rate was found
|
||||
if (baud_valid == false)
|
||||
{
|
||||
app_start(); // w/o valid baud rate jump t the app
|
||||
}
|
||||
|
||||
start_uart_bl(bl_baud); // This will create a 23 us wide low 'blip' on the TX line (until possibly fixed)
|
||||
am_util_delay_us(200); // At the minimum baud rate of 115200 one byte (10 bits with start/stop) takes 10/115200 or 87 us. 87+23 = 100, double to be safe
|
||||
|
||||
debug_printf("phase:\tconfirm bootloading entry\n");
|
||||
debug_printf("\tsending Artemis SVL version packet\n");
|
||||
svl_packet_send(&svl_packet_version); // when baud rate is determined send the version packet
|
||||
|
||||
debug_printf("\twaiting for bootloader confirmation\n");
|
||||
if (svl_packet_wait(&svl_packet_blmode) != 0)
|
||||
{ // wait for the bootloader to confirm bootloader mode entry
|
||||
debug_printf("\tno confirmation received\n");
|
||||
app_start(); // break to app
|
||||
}
|
||||
debug_printf("\tentering bootloader\n\n");
|
||||
|
||||
enter_bootload(); // Now we are locked in
|
||||
am_util_delay_ms(10);
|
||||
|
||||
am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI, 0); //Cause a system Power On Init to release as much of the stack as possible
|
||||
|
||||
debug_printf("ERROR - runoff");
|
||||
while (1)
|
||||
{ // Loop forever while sleeping.
|
||||
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Go to Deep Sleep.
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Function definitions below
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifdef DEBUG
|
||||
void start_uart_debug(void)
|
||||
{
|
||||
const am_hal_gpio_pincfg_t debug_uart_tx_pinconfig = UART_GPIO_PINCONFIG(DEBUG_UART_INST, TX, DEBUG_TX_PAD);
|
||||
const am_hal_gpio_pincfg_t debug_uart_rx_pinconfig = UART_GPIO_PINCONFIG(DEBUG_UART_INST, RX, DEBUG_RX_PAD);
|
||||
const am_hal_uart_config_t debug_uart_config = {
|
||||
// Standard UART settings: 115200-8-N-1
|
||||
.ui32BaudRate = DEBUG_BAUD_RATE,
|
||||
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
|
||||
.ui32Parity = AM_HAL_UART_PARITY_NONE,
|
||||
.ui32StopBits = AM_HAL_UART_ONE_STOP_BIT,
|
||||
.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
|
||||
|
||||
// Set TX and RX FIFOs to interrupt at half-full.
|
||||
.ui32FifoLevels = (AM_HAL_UART_TX_FIFO_1_2 |
|
||||
AM_HAL_UART_RX_FIFO_1_2),
|
||||
|
||||
// Buffers
|
||||
.pui8TxBuffer = NULL,
|
||||
.ui32TxBufferSize = 0,
|
||||
.pui8RxBuffer = NULL,
|
||||
.ui32RxBufferSize = 0,
|
||||
};
|
||||
|
||||
// Initialize the printf interface for UART output.
|
||||
am_hal_uart_initialize(DEBUG_UART_INST, &hUART_debug);
|
||||
am_hal_uart_power_control(hUART_debug, AM_HAL_SYSCTRL_WAKE, false);
|
||||
am_hal_uart_configure(hUART_debug, &debug_uart_config);
|
||||
|
||||
// Disable that pesky FIFO
|
||||
UARTn(DEBUG_UART_INST)->LCRH_b.FEN = 0;
|
||||
|
||||
// Enable the UART pins.
|
||||
am_hal_gpio_pinconfig(DEBUG_TX_PAD, debug_uart_tx_pinconfig);
|
||||
am_hal_gpio_pinconfig(DEBUG_RX_PAD, debug_uart_rx_pinconfig);
|
||||
|
||||
// Enable interrupts.
|
||||
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + DEBUG_UART_INST));
|
||||
am_hal_uart_interrupt_enable(hUART_debug, (AM_HAL_UART_INT_RX));
|
||||
}
|
||||
|
||||
void stop_uart_debug(void)
|
||||
{
|
||||
// Deinitialize the UART printf interface.
|
||||
am_hal_uart_power_control(hUART_debug, AM_HAL_SYSCTRL_DEEPSLEEP, false);
|
||||
am_hal_uart_deinitialize(hUART_debug);
|
||||
|
||||
// Re-enable that pesky FIFO
|
||||
UARTn(DEBUG_UART_INST)->LCRH_b.FEN = 1;
|
||||
|
||||
// Disable the UART pins.
|
||||
am_hal_gpio_pinconfig(DEBUG_TX_PAD, g_AM_HAL_GPIO_DISABLE);
|
||||
am_hal_gpio_pinconfig(DEBUG_RX_PAD, g_AM_HAL_GPIO_DISABLE);
|
||||
|
||||
// Disable interrupts.
|
||||
NVIC_DisableIRQ((IRQn_Type)(UART0_IRQn + DEBUG_UART_INST));
|
||||
am_hal_uart_interrupt_disable(hUART_debug, (AM_HAL_UART_INT_RX));
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
//*****************************************************************************
|
||||
void setup(void)
|
||||
{
|
||||
// Set the clock frequency.
|
||||
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
|
||||
|
||||
// Set the default cache configuration
|
||||
am_hal_cachectrl_config(&am_hal_cachectrl_defaults);
|
||||
am_hal_cachectrl_enable();
|
||||
|
||||
// Configure the stimer
|
||||
am_hal_stimer_int_enable(AM_HAL_STIMER_INT_OVERFLOW);
|
||||
NVIC_EnableIRQ(STIMER_IRQn);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ);
|
||||
|
||||
#ifdef DEBUG
|
||||
start_uart_debug();
|
||||
#endif
|
||||
|
||||
// Enable interrupts.
|
||||
am_hal_interrupt_master_enable();
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Un-set-up
|
||||
//
|
||||
//*****************************************************************************
|
||||
void unsetup(void)
|
||||
{
|
||||
disable_burst_mode();
|
||||
|
||||
// Deconfigure the stimer
|
||||
am_hal_stimer_int_disable(AM_HAL_STIMER_INT_OVERFLOW);
|
||||
NVIC_DisableIRQ(STIMER_IRQn);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE);
|
||||
am_hal_stimer_config(AM_HAL_STIMER_NO_CLK);
|
||||
|
||||
#ifdef DEBUG
|
||||
stop_uart_debug();
|
||||
#endif
|
||||
|
||||
// Disable interrupts.
|
||||
am_hal_interrupt_master_disable();
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Baud Rate Detect Phase
|
||||
//
|
||||
// ****************************************
|
||||
bool detect_baud_rate(uint32_t *baud)
|
||||
{
|
||||
uint32_t bl_entry_timeout_ms = 200;
|
||||
uint32_t bl_entry_timeout_start = millis();
|
||||
bool baud_is_valid = false;
|
||||
bool timed_out = true;
|
||||
|
||||
debug_printf("phase:\tdetect baud rate\n");
|
||||
|
||||
enable_burst_mode();
|
||||
|
||||
am_hal_gpio_pinconfig(BL_RX_PAD, g_AM_HAL_GPIO_INPUT_PULLUP);
|
||||
|
||||
ap3_gpio_enable_interrupts(BL_RX_PAD, AM_HAL_GPIO_PIN_INTDIR_LO2HI);
|
||||
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
am_hal_gpio_interrupt_enable(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
NVIC_EnableIRQ(GPIO_IRQn);
|
||||
|
||||
while ((millis() - bl_entry_timeout_start) < bl_entry_timeout_ms)
|
||||
{
|
||||
// try to detect baud rate
|
||||
|
||||
// debug_printf("\ttime (ms):\t%d\n", millis());
|
||||
|
||||
if (bl_baud_ticks_index == BL_BAUD_SAMPLES)
|
||||
{
|
||||
|
||||
// compute differences between samples
|
||||
for (uint8_t indi = 0; indi < (BL_BAUD_SAMPLES - 1); indi++)
|
||||
{
|
||||
bl_baud_ticks[indi] = bl_baud_ticks[indi + 1] - bl_baud_ticks[indi];
|
||||
}
|
||||
|
||||
float mean = 0.0;
|
||||
for (uint8_t indi = 0; indi < (BL_BAUD_SAMPLES - 1); indi++)
|
||||
{
|
||||
mean += bl_baud_ticks[indi];
|
||||
}
|
||||
mean /= (BL_BAUD_SAMPLES - 1);
|
||||
|
||||
if (mean < 3)
|
||||
{
|
||||
// invalid
|
||||
}
|
||||
else if ((mean >= 4) && (mean <= 8))
|
||||
{
|
||||
*baud = 921600;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 10) && (mean <= 14))
|
||||
{
|
||||
*baud = 460800;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 25) && (mean <= 30))
|
||||
{
|
||||
*baud = 230400;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 45) && (mean <= 55))
|
||||
{
|
||||
*baud = 115200;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else if ((mean >= 91) && (mean <= 111))
|
||||
{
|
||||
*baud = 57600;
|
||||
baud_is_valid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid
|
||||
}
|
||||
|
||||
if (baud_is_valid)
|
||||
{
|
||||
timed_out = false;
|
||||
}
|
||||
|
||||
break; // exit the timeout loop
|
||||
}
|
||||
}
|
||||
|
||||
am_hal_gpio_interrupt_disable(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
NVIC_DisableIRQ(GPIO_IRQn);
|
||||
|
||||
disable_burst_mode();
|
||||
|
||||
#ifdef DEBUG
|
||||
// show differences for debugging purposes
|
||||
debug_printf("\ttiming differences: { ");
|
||||
for (uint8_t indi = 0; indi < (BL_BAUD_SAMPLES - 1); indi++)
|
||||
{
|
||||
debug_printf("%d", bl_baud_ticks[indi]);
|
||||
if (indi < (BL_BAUD_SAMPLES - 2))
|
||||
{
|
||||
debug_printf(", ");
|
||||
}
|
||||
}
|
||||
debug_printf("}\n");
|
||||
#endif // DEBUG
|
||||
|
||||
if (!baud_is_valid)
|
||||
{
|
||||
debug_printf("\tbaud rate not detected.\n\t\trising edges:\t%d\n\t\ttimed out:\t%d\n\n", bl_baud_ticks_index, timed_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("\tdetected valid baud rate:\t%d\n\n", *baud);
|
||||
}
|
||||
|
||||
return baud_is_valid;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Start BL UART at desired baud
|
||||
//
|
||||
//*****************************************************************************
|
||||
void start_uart_bl(uint32_t baud)
|
||||
{
|
||||
const am_hal_gpio_pincfg_t bl_uart_tx_pinconfig = UART_GPIO_PINCONFIG(BL_UART_INST, TX, BL_TX_PAD);
|
||||
const am_hal_gpio_pincfg_t bl_uart_rx_pinconfig = UART_GPIO_PINCONFIG(BL_UART_INST, RX, BL_RX_PAD);
|
||||
am_hal_uart_config_t bl_uart_config =
|
||||
{
|
||||
// Standard UART settings: 115200-8-N-1
|
||||
.ui32BaudRate = baud,
|
||||
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
|
||||
.ui32Parity = AM_HAL_UART_PARITY_NONE,
|
||||
.ui32StopBits = AM_HAL_UART_ONE_STOP_BIT,
|
||||
.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
|
||||
|
||||
// Set TX and RX FIFOs to interrupt at half-full.
|
||||
.ui32FifoLevels = (AM_HAL_UART_TX_FIFO_1_2 |
|
||||
AM_HAL_UART_RX_FIFO_1_2),
|
||||
|
||||
// Buffers
|
||||
.pui8TxBuffer = NULL,
|
||||
.ui32TxBufferSize = 0,
|
||||
.pui8RxBuffer = NULL,
|
||||
.ui32RxBufferSize = 0,
|
||||
};
|
||||
|
||||
// Initialize the printf interface for UART output.
|
||||
am_hal_uart_initialize(BL_UART_INST, &hUART_bl);
|
||||
am_hal_uart_power_control(hUART_bl, AM_HAL_SYSCTRL_WAKE, false);
|
||||
am_hal_uart_configure(hUART_bl, &bl_uart_config);
|
||||
|
||||
// Disable that pesky FIFO
|
||||
UARTn(BL_UART_INST)->LCRH_b.FEN = 0;
|
||||
|
||||
// Enable the UART pins.
|
||||
am_hal_gpio_pinconfig(BL_TX_PAD, bl_uart_tx_pinconfig);
|
||||
am_hal_gpio_pinconfig(BL_RX_PAD, bl_uart_rx_pinconfig);
|
||||
|
||||
// Enable interrupts.
|
||||
NVIC_EnableIRQ((IRQn_Type)(UART0_IRQn + BL_UART_INST));
|
||||
am_hal_uart_interrupt_enable(hUART_bl, (AM_HAL_UART_INT_RX));
|
||||
|
||||
// Provide SVL Packet interfaces
|
||||
svl_packet_link_read_fn(art_svl_ringbuf_read, &bl_rx_ringbuf);
|
||||
svl_packet_link_avail_fn(art_svl_ringbuf_available, &bl_rx_ringbuf);
|
||||
svl_packet_link_millis_fn(millis);
|
||||
svl_packet_link_write_fn(svl_uart_write_byte, hUART_bl);
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Bootload phase
|
||||
//
|
||||
// ****************************************
|
||||
void enter_bootload(void)
|
||||
{
|
||||
enable_burst_mode();
|
||||
bool done = false;
|
||||
uint32_t frame_address = 0;
|
||||
uint16_t last_page_erased = 0;
|
||||
uint8_t retransmit = 0;
|
||||
static uint32_t frame_buffer[FRAME_BUFFER_SIZE];
|
||||
|
||||
svl_packet_t svl_packet_incoming_frame = {CMD_FRAME, (uint8_t *)frame_buffer, sizeof(frame_buffer) / sizeof(uint8_t), sizeof(frame_buffer) / sizeof(uint8_t)};
|
||||
svl_packet_t svl_packet_retry = {CMD_RETRY, NULL, 0, 0};
|
||||
svl_packet_t svl_packet_next = {CMD_NEXT, NULL, 0, 0};
|
||||
|
||||
debug_printf("phase:\tbootload\n");
|
||||
|
||||
while (!done)
|
||||
{
|
||||
|
||||
if (retransmit != 0)
|
||||
{
|
||||
debug_printf("\trequesting retransmission\n");
|
||||
svl_packet_send((svl_packet_t *)&svl_packet_retry); // Ask to retransmit
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("\trequesting next app frame\n");
|
||||
svl_packet_send((svl_packet_t *)&svl_packet_next); // Ask for the next frame packet
|
||||
}
|
||||
retransmit = 0;
|
||||
|
||||
uint8_t stat = svl_packet_wait(&svl_packet_incoming_frame);
|
||||
if (stat != 0)
|
||||
{ // wait for either a frame or the done command
|
||||
debug_printf("\t\terror receiving packet (%d)\n", stat);
|
||||
retransmit = 1;
|
||||
am_util_delay_us(177000); //Worst case: wait 177ms for 2048 byte transfer at 115200bps to complete
|
||||
|
||||
//Flush the buffers to remove any inbound or outbound garbage
|
||||
bl_rx_ringbuf.r_offset = 0;
|
||||
bl_rx_ringbuf.w_offset = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// debug_printf("Successfully received incoming frame packet (todo: add extra details in debug)\n", stat);
|
||||
|
||||
if (svl_packet_incoming_frame.cmd == CMD_FRAME)
|
||||
{
|
||||
debug_printf("\t\treceived an app frame\n");
|
||||
if (handle_frame_packet(&svl_packet_incoming_frame, &frame_address, &last_page_erased) != 0)
|
||||
{
|
||||
// debug_printf("\t\t\tbootload error - packet could not be handled\n");
|
||||
retransmit = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (svl_packet_incoming_frame.cmd == CMD_DONE)
|
||||
{
|
||||
debug_printf("\t\treceived done signal!\n\n");
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug_printf("bootload error - unknown command\n");
|
||||
retransmit = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// finish bootloading
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Handle a frame packet
|
||||
//
|
||||
// ****************************************
|
||||
uint8_t handle_frame_packet(svl_packet_t *packet, uint32_t *p_frame_address, uint16_t *p_last_page_erased)
|
||||
{
|
||||
// debug_printf("\t\thandling frame\n");
|
||||
uint32_t num_words = (packet->pl_len / 4);
|
||||
|
||||
debug_printf("\t\tframe_address = 0x%08X, num_words = %d\n", *(p_frame_address), num_words);
|
||||
|
||||
// Check payload length is multiple of words
|
||||
if ((packet->pl_len % 4))
|
||||
{
|
||||
debug_printf("Error: frame packet not integer multiple of words (4 bytes per word)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t i32ReturnCode = 0;
|
||||
uint32_t offset_address = (*(p_frame_address) + USERCODE_OFFSET);
|
||||
if ((*p_last_page_erased) < AM_HAL_FLASH_ADDR2PAGE(offset_address))
|
||||
{ // Prevent erasing partially-filled pages
|
||||
// debug_printf("Erasing instance %d, page %d\n\r", AM_HAL_FLASH_ADDR2INST( offset_address ), AM_HAL_FLASH_ADDR2PAGE(offset_address) );
|
||||
|
||||
//Erase the 8k page for this address
|
||||
i32ReturnCode = am_hal_flash_page_erase(AM_HAL_FLASH_PROGRAM_KEY, AM_HAL_FLASH_ADDR2INST(offset_address), AM_HAL_FLASH_ADDR2PAGE(offset_address));
|
||||
*(p_last_page_erased) = AM_HAL_FLASH_ADDR2PAGE(offset_address);
|
||||
|
||||
if (i32ReturnCode)
|
||||
{
|
||||
debug_printf("FLASH_MASS_ERASE i32ReturnCode = 0x%x.\n\r", i32ReturnCode);
|
||||
}
|
||||
}
|
||||
|
||||
//Record the array
|
||||
//debug_printf("Recording %d words (%d bytes) to memory\n", num_words, 4 * num_words);
|
||||
i32ReturnCode = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY, (uint32_t *)packet->pl, (uint32_t *)(*(p_frame_address) + USERCODE_OFFSET), num_words);
|
||||
if (i32ReturnCode)
|
||||
{
|
||||
debug_printf("FLASH_WRITE error = 0x%x.\n\r", i32ReturnCode);
|
||||
return 1;
|
||||
}
|
||||
*(p_frame_address) += num_words * 4;
|
||||
|
||||
// debug_printf("Array recorded to flash\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Jump to the application
|
||||
//
|
||||
// ****************************************
|
||||
void app_start(void)
|
||||
{
|
||||
// debug_printf("\n\t-- app start --\n");
|
||||
// #ifdef DEBUG
|
||||
// #ifdef DEBUG_PRINT_APP
|
||||
// uint32_t start_address = USERCODE_OFFSET; // Print a section of flash
|
||||
// debug_printf("Printing page starting at offset 0x%04X\n", start_address);
|
||||
// #ifdef APP_PRINT_PRETTY
|
||||
// for (uint16_t x = 0; x < 512*APP_PRINT_NUM_PAGE; x++){
|
||||
// if (x % 8 == 0){
|
||||
// debug_printf("\nAdr: 0x%04X", start_address + (x * 4));
|
||||
// }
|
||||
// debug_printf(" 0x%08X", *(uint32_t *)(start_address + (x * 4)));
|
||||
// }
|
||||
// debug_printf("\n");
|
||||
// #else
|
||||
// for (uint16_t x = 0; x < 512*APP_PRINT_NUM_PAGE; x++){
|
||||
// if (x % 4 == 0){
|
||||
// debug_printf("\n");
|
||||
// }
|
||||
// uint32_t wor = *(uint32_t *)(start_address + (x * 4));
|
||||
// debug_printf("%02x%02x %02x%02x", (wor & 0x000000FF), (wor & 0x0000FF00) >> 8, (wor & 0x00FF0000) >> 16, (wor & 0xFF000000) >> 24 );
|
||||
// if( (x%4) != 3 ){
|
||||
// debug_printf(" ");
|
||||
// }
|
||||
// }
|
||||
// debug_printf("\n");
|
||||
// #endif // APP_PRINT_PRETTY
|
||||
// #endif // DEBUG_PRINT_APP
|
||||
// #endif // DEBUG
|
||||
|
||||
void *entryPoint = (void *)(*((uint32_t *)(USERCODE_OFFSET + 4)));
|
||||
debug_printf("\nJump to App at 0x%08X\n\n", (uint32_t)entryPoint);
|
||||
am_util_delay_ms(10); // Wait for prints to complete
|
||||
unsetup(); // Undoes configuration to provide users with a clean slate
|
||||
goto *entryPoint; // Jump to start of user code
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
//
|
||||
// Debug printf function
|
||||
//
|
||||
// ****************************************
|
||||
void debug_printf(char *fmt, ...)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
char debug_buffer[DEBUG_UART_BUF_LEN];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(debug_buffer, DEBUG_UART_BUF_LEN, (const char *)fmt, args);
|
||||
va_end(args);
|
||||
|
||||
svl_uart_print(hUART_debug, debug_buffer);
|
||||
#endif //DEBUG
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART interrupt handlers
|
||||
//
|
||||
//*****************************************************************************
|
||||
void am_uart_isr(void)
|
||||
{
|
||||
// Service the FIFOs as necessary, and clear the interrupts.
|
||||
#if BL_UART_INST == 0
|
||||
uint32_t ui32Status, ui32Idle;
|
||||
am_hal_uart_interrupt_status_get(hUART_bl, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_bl, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_bl, ui32Status, &ui32Idle);
|
||||
if (ui32Status & AM_HAL_UART_INT_RX)
|
||||
{
|
||||
uint8_t c = 0x00;
|
||||
if (svl_uart_read(hUART_bl, (char *)&c, 1) != 0)
|
||||
{
|
||||
art_svl_ringbuf_write(&bl_rx_ringbuf, c);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
am_hal_uart_interrupt_status_get(hUART_debug, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_debug, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_debug, ui32Status, &ui32Idle);
|
||||
#endif // DEBUG
|
||||
#endif // BL_UART_INST == 0
|
||||
}
|
||||
|
||||
void am_uart1_isr(void)
|
||||
{
|
||||
// Service the FIFOs as necessary, and clear the interrupts.
|
||||
#if BL_UART_INST == 1
|
||||
uint32_t ui32Status, ui32Idle;
|
||||
am_hal_uart_interrupt_status_get(hUART_bl, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_bl, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_bl, ui32Status, &ui32Idle);
|
||||
if (ui32Status & AM_HAL_UART_INT_RX)
|
||||
{
|
||||
uint8_t c = 0x00;
|
||||
if (read(hUART_bl, &c, 1) != 0)
|
||||
{
|
||||
art_svl_ringbuf_write(&bl_rx_ringbuf, c);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
uint32_t ui32Status, ui32Idle;
|
||||
am_hal_uart_interrupt_status_get(hUART_debug, &ui32Status, true);
|
||||
am_hal_uart_interrupt_clear(hUART_debug, ui32Status);
|
||||
am_hal_uart_interrupt_service(hUART_debug, ui32Status, &ui32Idle);
|
||||
#endif // DEBUG
|
||||
#endif // BL_UART_INST == 0
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// GPIO interrupt handler
|
||||
//
|
||||
//*****************************************************************************
|
||||
void am_gpio_isr(void)
|
||||
{
|
||||
am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(BL_RX_PAD));
|
||||
if (bl_baud_ticks_index < BL_BAUD_SAMPLES)
|
||||
{
|
||||
bl_baud_ticks[bl_baud_ticks_index++] = CTIMER->STTMR;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// STimer interrupt handler
|
||||
//
|
||||
//*****************************************************************************
|
||||
void am_stimer_isr(void)
|
||||
{
|
||||
am_hal_stimer_int_clear(AM_HAL_STIMER_INT_OVERFLOW);
|
||||
ap3_stimer_overflows += 1;
|
||||
// At the fastest rate (3MHz) the 64 bits of the stimer
|
||||
// along with this overflow counter can keep track of
|
||||
// the time for ~ 195,000 years without wrapping to 0
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
#include "svl_packet.h"
|
||||
|
||||
void *read_param = NULL;
|
||||
void *write_param = NULL;
|
||||
void *avail_param = NULL;
|
||||
|
||||
svl_packet_read_byte_fn_t read_fn = NULL;
|
||||
svl_packet_write_byte_fn_t write_fn = NULL;
|
||||
svl_packet_avail_bytes_fn_t avail_fn = NULL;
|
||||
svl_packet_millis_fn_t millis_fn = NULL;
|
||||
|
||||
uint8_t CRCL, CRCH;
|
||||
|
||||
uint16_t CRC_Table[8 * 32] = {
|
||||
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
|
||||
0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
|
||||
0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
|
||||
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
|
||||
0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
|
||||
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
|
||||
0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
|
||||
0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
|
||||
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
|
||||
0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
|
||||
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
|
||||
0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
|
||||
0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
|
||||
0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
|
||||
0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
|
||||
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
|
||||
0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202};
|
||||
|
||||
//Update CRC with given byte
|
||||
inline __attribute__((always_inline)) void updateCRC(uint8_t num)
|
||||
{
|
||||
uint16_t tableAddr = (num ^ CRCH);
|
||||
CRCH = (CRC_Table[tableAddr] >> 8) ^ CRCL;
|
||||
CRCL = (CRC_Table[tableAddr] & 0x00FF);
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_read_byte(uint8_t *c)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (read_fn != NULL)
|
||||
{
|
||||
retval = read_fn(read_param, c);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_write_byte(uint8_t c)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (write_fn != NULL)
|
||||
{
|
||||
retval = write_fn(write_param, c);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_avail_bytes(void)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (avail_fn != NULL)
|
||||
{
|
||||
retval = avail_fn(avail_param);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline)) size_t svl_packet_millis(void)
|
||||
{
|
||||
size_t retval = 0x00;
|
||||
if (millis_fn != NULL)
|
||||
{
|
||||
retval = millis_fn();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void svl_packet_link_read_fn(svl_packet_read_byte_fn_t fn, void *param)
|
||||
{
|
||||
read_param = param;
|
||||
read_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_link_write_fn(svl_packet_write_byte_fn_t fn, void *param)
|
||||
{
|
||||
write_param = param;
|
||||
write_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_link_avail_fn(svl_packet_avail_bytes_fn_t fn, void *param)
|
||||
{
|
||||
avail_param = param;
|
||||
avail_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_link_millis_fn(svl_packet_millis_fn_t fn)
|
||||
{
|
||||
millis_fn = fn;
|
||||
}
|
||||
|
||||
void svl_packet_send(svl_packet_t *packet)
|
||||
{
|
||||
CRCL = 0;
|
||||
CRCH = 0;
|
||||
updateCRC(packet->cmd); //Add this byte to CRC
|
||||
for (uint32_t x = 0; x < packet->pl_len; x++)
|
||||
{
|
||||
updateCRC(*(packet->pl + x)); //Add this byte to CRC
|
||||
}
|
||||
|
||||
svl_packet_write_byte(((packet->pl_len + 3) >> 8)); // len high byte (including command and CRC bytes)
|
||||
svl_packet_write_byte(((packet->pl_len + 3) & 0xFF)); // len low byte (including command and CRC bytes)
|
||||
|
||||
svl_packet_write_byte((packet->cmd)); // command byte
|
||||
|
||||
if ((packet->pl != NULL) && (packet->pl_len != 0))
|
||||
{
|
||||
for (uint16_t indi = 0; indi < packet->pl_len; indi++)
|
||||
{ // payload
|
||||
svl_packet_write_byte(*(packet->pl + indi));
|
||||
}
|
||||
}
|
||||
|
||||
svl_packet_write_byte(CRCH); // CRC H
|
||||
svl_packet_write_byte(CRCL); // CRC L
|
||||
}
|
||||
|
||||
uint8_t svl_packet_wait(svl_packet_t *packet)
|
||||
{
|
||||
|
||||
// wait for 2 bytes (the length bytes)
|
||||
// wait for length bytes to come in
|
||||
// make sure that 'length' bytes are enough to satisfy the desired payload length
|
||||
|
||||
if (packet == NULL)
|
||||
{
|
||||
return (SVL_PACKET_ERR);
|
||||
}
|
||||
|
||||
const uint8_t num_bytes_length = 2;
|
||||
if (svl_packet_wait_bytes(num_bytes_length))
|
||||
{
|
||||
return (SVL_PACKET_ERR_TIMEOUT | SVL_PACKET_LEN);
|
||||
}
|
||||
uint16_t len = svl_packet_get_uint16_t();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return (SVL_PACKET_ERR_ZLP);
|
||||
}
|
||||
if ((len - 3) > packet->max_pl_len)
|
||||
{
|
||||
return (SVL_PACKET_ERR_MEM | SVL_PACKET_PL);
|
||||
}
|
||||
|
||||
//Wait for entire packet to come in
|
||||
if (svl_packet_wait_bytes(len))
|
||||
return (SVL_PACKET_ERR_TIMEOUT | SVL_PACKET_PL);
|
||||
|
||||
uint8_t incoming;
|
||||
CRCL = 0;
|
||||
CRCH = 0;
|
||||
|
||||
//Get command byte
|
||||
svl_packet_read_byte(&incoming);
|
||||
packet->cmd = incoming;
|
||||
updateCRC(incoming); //Add this byte to CRC
|
||||
|
||||
packet->pl_len = (len - 3);
|
||||
|
||||
//Now read the data coming in
|
||||
if ((packet->pl != NULL) && (packet->max_pl_len != 0))
|
||||
{
|
||||
for (uint32_t x = 0; x < packet->pl_len; x++)
|
||||
{
|
||||
svl_packet_read_byte(&incoming);
|
||||
|
||||
updateCRC(incoming); //Add this byte to CRC
|
||||
|
||||
*(packet->pl + x) = incoming; //Fill payload with data
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t crc = svl_packet_get_uint16_t(); //Read final two bytes into CRC
|
||||
|
||||
uint16_t check = ((uint16_t)CRCH << 8) | CRCL;
|
||||
|
||||
if (crc != check)
|
||||
{
|
||||
return (SVL_PACKET_ERR_CRC);
|
||||
}
|
||||
|
||||
return (SVL_PACKET_OK);
|
||||
}
|
||||
|
||||
uint16_t svl_packet_get_uint16_t(void)
|
||||
{
|
||||
uint8_t h = 0x00;
|
||||
uint8_t l = 0x00;
|
||||
svl_packet_read_byte(&h);
|
||||
svl_packet_read_byte(&l);
|
||||
return (((uint16_t)h << 8) | (l & 0xFF));
|
||||
}
|
||||
|
||||
uint8_t svl_packet_wait_bytes(uint32_t num)
|
||||
{
|
||||
uint32_t timeout_ms = 500;
|
||||
uint32_t start = svl_packet_millis();
|
||||
uint32_t avail = 0;
|
||||
|
||||
while ((svl_packet_millis() - start) < timeout_ms)
|
||||
{
|
||||
avail = svl_packet_avail_bytes();
|
||||
if (avail >= num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// debug_printf("only got %d bytes...\n",avail);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef _SVL_PACKET_H_
|
||||
#define _SVL_PACKET_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
typedef struct _svl_packet_t
|
||||
{ // An SVL3 packet consists of 5+N bytes. N is the length of the data payload, and there are 5 bytes that are always transmitted
|
||||
// len // 2 - length of the remainder of the packet (pllen + 3) (note, this is automatically calculated)
|
||||
uint8_t cmd; // 1 - The command
|
||||
uint8_t *pl; // N - The payload (pointer)
|
||||
uint16_t pl_len; // - Length of the payload in bytes (note, this is not transmitted across the line, just used internally)
|
||||
// crc // 2 - CRC16 on the command and the payload. poly = 0x8005, nothing extra or fancy. Byte order MSB first, bit order MSB first
|
||||
uint16_t max_pl_len; // - This is the number of bytes pointed to by 'pl'
|
||||
} svl_packet_t;
|
||||
|
||||
enum
|
||||
{
|
||||
SVL_PACKET_OK = 0x00,
|
||||
SVL_PACKET_ERR = 0x01, // general error
|
||||
SVL_PACKET_ERR_TIMEOUT = 0x02, // timeout
|
||||
SVL_PACKET_ERR_ZLP = 0x04, // zero length packet
|
||||
SVL_PACKET_ERR_MEM = 0x08, // not enough space to receive packet
|
||||
SVL_PACKET_ERR_CRC = 0x10, // crc mismatch
|
||||
|
||||
SVL_PACKET_LEN = 0x80, // flag indicating 'len' header
|
||||
SVL_PACKET_PL = 0x40, // flag indicating payload
|
||||
};
|
||||
|
||||
typedef size_t (*svl_packet_read_byte_fn_t)(void *, uint8_t *);
|
||||
typedef size_t (*svl_packet_write_byte_fn_t)(void *, uint8_t);
|
||||
typedef size_t (*svl_packet_avail_bytes_fn_t)(void *);
|
||||
typedef size_t (*svl_packet_millis_fn_t)(void);
|
||||
|
||||
void svl_packet_link_read_fn(svl_packet_read_byte_fn_t fn, void *param);
|
||||
void svl_packet_link_write_fn(svl_packet_write_byte_fn_t fn, void *param);
|
||||
void svl_packet_link_avail_fn(svl_packet_avail_bytes_fn_t fn, void *param);
|
||||
void svl_packet_link_millis_fn(svl_packet_millis_fn_t fn);
|
||||
|
||||
void svl_packet_send(svl_packet_t *packet);
|
||||
uint8_t svl_packet_wait(svl_packet_t *packet);
|
||||
|
||||
uint16_t svl_packet_get_uint16_t(void);
|
||||
uint8_t svl_packet_wait_bytes(uint32_t num);
|
||||
|
||||
#endif // _SVL_PACKET_H_
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "svl_ringbuf.h"
|
||||
|
||||
size_t art_svl_ringbuf_init( void* vrb, uint8_t* buf, size_t len ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
rb->buf = buf;
|
||||
rb->len = len;
|
||||
rb->r_offset = 0;
|
||||
rb->w_offset = 0;
|
||||
|
||||
return rb->len;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_available( void* vrb ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
size_t avail = 0x00;
|
||||
if((rb->w_offset) >= (rb->r_offset)){
|
||||
avail = rb->w_offset - rb->r_offset;
|
||||
}else{
|
||||
avail = rb->len - (rb->r_offset - rb->w_offset);
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_bytes_free( void* vrb ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
size_t friegh = 0x00;
|
||||
if((rb->w_offset) >= (rb->r_offset)){
|
||||
friegh = rb->len - rb->w_offset + rb->r_offset -1;
|
||||
}else{
|
||||
friegh = rb->r_offset - rb->w_offset - 1;
|
||||
}
|
||||
return friegh;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_write( void* vrb, uint8_t c ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
if(art_svl_ringbuf_bytes_free(rb) > 0){
|
||||
*(rb->buf + rb->w_offset) = c;
|
||||
rb->w_offset++;
|
||||
if(rb->w_offset >= rb->len){
|
||||
rb->w_offset = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t art_svl_ringbuf_read( void* vrb, uint8_t* c ){
|
||||
if( vrb == NULL ){ return 0; }
|
||||
art_svl_ringbuf_t* rb = (art_svl_ringbuf_t*)vrb;
|
||||
|
||||
if(art_svl_ringbuf_available(rb) > 0){
|
||||
*c = *(rb->buf + rb->r_offset);
|
||||
rb->r_offset++;
|
||||
if(rb->r_offset >= rb->len){
|
||||
rb->r_offset = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef _SVL_RINGBUF_H_
|
||||
#define _SVL_RINGBUF_H_
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
typedef struct _art_svl_ringbuf_t {
|
||||
uint8_t* buf;
|
||||
size_t len;
|
||||
volatile size_t r_offset;
|
||||
volatile size_t w_offset;
|
||||
}art_svl_ringbuf_t;
|
||||
|
||||
size_t art_svl_ringbuf_init ( void* rb, uint8_t* buf, size_t len );
|
||||
size_t art_svl_ringbuf_available ( void* rb );
|
||||
size_t art_svl_ringbuf_bytes_free ( void* rb );
|
||||
size_t art_svl_ringbuf_write ( void* rb, uint8_t c );
|
||||
size_t art_svl_ringbuf_read ( void* rb, uint8_t* c );
|
||||
|
||||
|
||||
#endif // _SVL_RINGBUF_H_
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "svl_uart.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART read buffer
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_read(void *pHandle, char* buf, size_t len){
|
||||
uint32_t ui32BytesRead = 0x00;
|
||||
am_hal_uart_transfer_t sRead = {
|
||||
.ui32Direction = AM_HAL_UART_READ,
|
||||
.pui8Data = (uint8_t*)buf,
|
||||
.ui32NumBytes = len,
|
||||
.ui32TimeoutMs = 0,
|
||||
.pui32BytesTransferred = &ui32BytesRead,
|
||||
};
|
||||
am_hal_uart_transfer(pHandle, &sRead);
|
||||
return ui32BytesRead;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART write buffer
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_write(void *pHandle, char* buf, size_t len){
|
||||
uint32_t ui32BytesWritten = 0;
|
||||
const am_hal_uart_transfer_t sUartWrite =
|
||||
{
|
||||
.ui32Direction = AM_HAL_UART_WRITE,
|
||||
.pui8Data = (uint8_t*) buf,
|
||||
.ui32NumBytes = len,
|
||||
.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER,
|
||||
.pui32BytesTransferred = &ui32BytesWritten,
|
||||
};
|
||||
|
||||
am_hal_uart_transfer(pHandle, &sUartWrite);
|
||||
|
||||
return ui32BytesWritten;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART write byte
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_write_byte(void *pHandle, uint8_t c){
|
||||
return svl_uart_write(pHandle, (char*)&c, 1);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// UART send string
|
||||
//
|
||||
//*****************************************************************************
|
||||
size_t svl_uart_print(void *pHandle, char* str){
|
||||
uint32_t ui32StrLen = 0;
|
||||
while (str[ui32StrLen] != 0){ ui32StrLen++; } // Measure the length of the string.
|
||||
return svl_uart_write( pHandle, str, ui32StrLen);
|
||||
|
||||
// uint16_t indi = 0;
|
||||
// while((*(debug_buffer+indi)!='\0') && (indi < DEBUG_UART_BUF_LEN)){
|
||||
// svl_uart_write(hUART_debug, debug_buffer+indi, 1);
|
||||
// indi++;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef _SVL_UART_H_
|
||||
#define _SVL_UART_H_
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
|
||||
size_t svl_uart_read (void *pHandle, char* buf, size_t len);
|
||||
size_t svl_uart_write (void *pHandle, char* buf, size_t len);
|
||||
size_t svl_uart_write_byte (void *pHandle, uint8_t c);
|
||||
size_t svl_uart_print (void *pHandle, char* str);
|
||||
|
||||
|
||||
#endif // _SVL_UART_H_
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "svl_utils.h"
|
||||
|
||||
#define AP3_STIMER_FREQ_HZ (3000000)
|
||||
#define AP3_STIMER_FREQ_KHZ (AP3_STIMER_FREQ_HZ / 1000)
|
||||
#define AP3_STIMER_FREQ_MHZ (AP3_STIMER_FREQ_HZ / 1000000)
|
||||
|
||||
volatile uint32_t ap3_stimer_overflows = 0x00;
|
||||
uint64_t ticks = 0;
|
||||
|
||||
void _fill_ticks(void)
|
||||
{
|
||||
ticks = ap3_stimer_overflows;
|
||||
ticks <<= 32;
|
||||
ticks |= (am_hal_stimer_counter_get() & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
size_t millis(void){
|
||||
_fill_ticks();
|
||||
return (uint32_t)(ticks / AP3_STIMER_FREQ_KHZ);
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Burst mode
|
||||
//
|
||||
//*****************************************************************************
|
||||
bool enable_burst_mode(void)
|
||||
{
|
||||
// Check that the Burst Feature is available.
|
||||
am_hal_burst_avail_e eBurstModeAvailable;
|
||||
if (AM_HAL_STATUS_SUCCESS != am_hal_burst_mode_initialize(&eBurstModeAvailable))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Put the MCU into "Burst" mode.
|
||||
am_hal_burst_mode_e eBurstMode;
|
||||
if (AM_HAL_STATUS_SUCCESS != am_hal_burst_mode_enable(&eBurstMode))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
//Turns main processor from 96MHz to 48MHz
|
||||
//Returns false if disable fails
|
||||
bool disable_burst_mode(void)
|
||||
{
|
||||
am_hal_burst_mode_e eBurstMode;
|
||||
if (AM_HAL_STATUS_SUCCESS == am_hal_burst_mode_disable(&eBurstMode))
|
||||
{
|
||||
if (AM_HAL_NORMAL_MODE != eBurstMode)
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// Local defines. Copied from am_hal_gpio.c
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Generally define GPIO PADREG and GPIOCFG bitfields
|
||||
//
|
||||
#define PADREG_FLD_76_S 6
|
||||
#define PADREG_FLD_FNSEL_S 3
|
||||
#define PADREG_FLD_DRVSTR_S 2
|
||||
#define PADREG_FLD_INPEN_S 1
|
||||
#define PADREG_FLD_PULLUP_S 0
|
||||
|
||||
#define GPIOCFG_FLD_INTD_S 3
|
||||
#define GPIOCFG_FLD_OUTCFG_S 1
|
||||
#define GPIOCFG_FLD_INCFG_S 0
|
||||
|
||||
uint32_t ap3_gpio_enable_interrupts(uint32_t ui32Pin, uint32_t eIntDir){
|
||||
uint32_t ui32Padreg, ui32AltPadCfg, ui32GPCfg;
|
||||
bool bClearEnable = false;
|
||||
|
||||
|
||||
ui32GPCfg = ui32Padreg = ui32AltPadCfg = 0;
|
||||
ui32GPCfg |= (((eIntDir >> 0) & 0x1) << GPIOCFG_FLD_INTD_S) | (((eIntDir >> 1) & 0x1) << GPIOCFG_FLD_INCFG_S);
|
||||
|
||||
uint32_t ui32GPCfgAddr;
|
||||
uint32_t ui32GPCfgClearMask;
|
||||
uint32_t ui32GPCfgShft;
|
||||
|
||||
ui32GPCfgShft = ((ui32Pin & 0x7) << 2);
|
||||
|
||||
ui32GPCfgAddr = AM_REGADDR(GPIO, CFGA) + ((ui32Pin >> 1) & ~0x3);
|
||||
ui32GPCfgClearMask = ~((uint32_t)0xF << ui32GPCfgShft);
|
||||
|
||||
ui32GPCfg <<= ui32GPCfgShft;
|
||||
|
||||
AM_CRITICAL_BEGIN
|
||||
|
||||
if (bClearEnable)
|
||||
{
|
||||
am_hal_gpio_output_tristate_disable(ui32Pin);
|
||||
}
|
||||
|
||||
GPIO->PADKEY = GPIO_PADKEY_PADKEY_Key;
|
||||
|
||||
// Here's where the magic happens
|
||||
AM_REGVAL(ui32GPCfgAddr) = (AM_REGVAL(ui32GPCfgAddr) & ui32GPCfgClearMask) | ui32GPCfg;
|
||||
|
||||
GPIO->PADKEY = 0;
|
||||
|
||||
AM_CRITICAL_END
|
||||
|
||||
return AM_HAL_STATUS_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _SVL_UTILS_H_
|
||||
#define _SVL_UTILS_H_
|
||||
|
||||
#include "am_mcu_apollo.h"
|
||||
#include "am_bsp.h"
|
||||
#include "am_util.h"
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
void _fill_ticks(void);
|
||||
size_t millis(void);
|
||||
bool enable_burst_mode(void);
|
||||
bool disable_burst_mode(void);
|
||||
uint32_t ap3_gpio_enable_interrupts(uint32_t ui32Pin, uint32_t eIntDir);
|
||||
|
||||
extern volatile uint32_t ap3_stimer_overflows;
|
||||
|
||||
#endif // _SVL_UTILS_H_
|
||||
Reference in New Issue
Block a user