Compare commits
No commits in common. "549ab46d2fe06e37771ee750d0b7ac8b68ad3451" and "c6d76baa0aab7c6de2e22de3f4854121bc287b8f" have entirely different histories.
549ab46d2f
...
c6d76baa0a
|
@ -1,30 +0,0 @@
|
|||
/**
|
||||
*********************************************************************
|
||||
*
|
||||
* @file NVmem.h
|
||||
* @brief
|
||||
*
|
||||
* @date 2024-07-13 12:24:17
|
||||
* @author CT
|
||||
*
|
||||
* @details
|
||||
*
|
||||
*************************************************************************
|
||||
**/
|
||||
|
||||
#ifndef _NVMEM_H_
|
||||
#define _NVMEM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define WRITE_TIMEOUT (6000u) // 6s
|
||||
#define NVMEM_SIZE (2048u) // in bytes
|
||||
#define NVMEM_ADDR (0x8050000)
|
||||
|
||||
int32_t NVmem_init(void);
|
||||
void NVmem_service(void);
|
||||
int32_t NVmem_write(uint8_t* data, uint32_t addr, uint32_t len);
|
||||
int32_t NVmem_write_immediate(uint8_t* data, uint32_t addr, uint32_t len);
|
||||
int32_t NVmem_read(uint8_t* data, uint32_t addr, uint32_t len);
|
||||
|
||||
#endif // _NVMEM_H_
|
|
@ -1,93 +0,0 @@
|
|||
/**
|
||||
*********************************************************************
|
||||
*
|
||||
* @file cir_buf.h
|
||||
* @brief Circular buffer header file
|
||||
*
|
||||
* @date 2024-04-21 18:36:52
|
||||
* @author CT
|
||||
*
|
||||
* @details Provides an interface for creating and interacting with circular
|
||||
* buffers.
|
||||
*
|
||||
*************************************************************************
|
||||
**/
|
||||
|
||||
#ifndef _CIR_BUF_H_
|
||||
#define _CIR_BUF_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/// Opaque circular buffer structure
|
||||
typedef struct circular_buf_t circular_buf_t;
|
||||
|
||||
/// Handle type, the way users interact with the API
|
||||
typedef circular_buf_t* cbuf_handle_t;
|
||||
|
||||
/// Pass in a storage buffer and size, returns a circular buffer handle
|
||||
/// Requires: buffer is not NULL, size > 0 (size > 1 for the threadsafe
|
||||
// version, because it holds size - 1 elements)
|
||||
/// Ensures: me has been created and is returned in an empty state
|
||||
cbuf_handle_t circular_buf_init(uint8_t* buffer, size_t size);
|
||||
|
||||
/// Free a circular buffer structure
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Does not free data buffer; owner is responsible for that
|
||||
void circular_buf_free(cbuf_handle_t me);
|
||||
|
||||
/// Reset the circular buffer to empty, head == tail. Data not cleared
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
void circular_buf_reset(cbuf_handle_t me);
|
||||
|
||||
/// Put that continues to add data if the buffer is full
|
||||
/// Old data is overwritten
|
||||
/// Note: if you are using the threadsafe version, this API cannot be used, because
|
||||
/// it modifies the tail pointer in some cases. Use circular_buf_try_put instead.
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
void circular_buf_put(cbuf_handle_t me, uint8_t data);
|
||||
|
||||
/// Put that rejects new data if the buffer is full
|
||||
/// Note: if you are using the threadsafe version, *this* is the put you should use
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Returns 0 on success, -1 if buffer is full
|
||||
int circular_buf_try_put(cbuf_handle_t me, uint8_t data);
|
||||
|
||||
/// Retrieve a value from the buffer
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Returns 0 on success, -1 if the buffer is empty
|
||||
int circular_buf_get(cbuf_handle_t me, uint8_t* data);
|
||||
|
||||
/// Checks if the buffer is empty
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Returns true if the buffer is empty
|
||||
bool circular_buf_empty(cbuf_handle_t me);
|
||||
|
||||
/// Checks if the buffer is full
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Returns true if the buffer is full
|
||||
bool circular_buf_full(cbuf_handle_t me);
|
||||
|
||||
/// Check the capacity of the buffer
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Returns the maximum capacity of the buffer
|
||||
size_t circular_buf_capacity(cbuf_handle_t me);
|
||||
|
||||
/// Check the number of elements stored in the buffer
|
||||
/// Requires: me is valid and created by circular_buf_init
|
||||
/// Returns the current number of elements in the buffer
|
||||
size_t circular_buf_size(cbuf_handle_t me);
|
||||
|
||||
/// Look ahead at values stored in the circular buffer without removing the data
|
||||
/// Requires:
|
||||
/// - me is valid and created by circular_buf_init
|
||||
/// - look_ahead_counter is less than or equal to the value returned by circular_buf_size()
|
||||
/// Returns 0 if successful, -1 if data is not available
|
||||
int circular_buf_peek(cbuf_handle_t me, uint8_t* data, unsigned int look_ahead_counter);
|
||||
|
||||
// TODO: int circular_buf_get_range(circular_buf_t me, uint8_t *data, size_t len);
|
||||
// TODO: int circular_buf_put_range(circular_buf_t me, uint8_t * data, size_t len);
|
||||
|
||||
|
||||
#endif /* _CIR_BUF_H_ */
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
*********************************************************************
|
||||
*
|
||||
* @file console.h
|
||||
* @brief
|
||||
*
|
||||
* @date 2024-04-14 19:12:40
|
||||
* @author CT
|
||||
*
|
||||
* @details
|
||||
*
|
||||
*************************************************************************
|
||||
**/
|
||||
|
||||
#ifndef _CONSOLE_H_
|
||||
#define _CONSOLE_H_
|
||||
|
||||
#include "main.h"
|
||||
#include "cir_buf.h"
|
||||
|
||||
void console_init(config_data_u_t* config_data);
|
||||
void console_service(void);
|
||||
int console_push(uint8_t data);
|
||||
|
||||
|
||||
#endif // _CONOSLE_H_
|
|
@ -36,20 +36,7 @@ extern "C" {
|
|||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN ET */
|
||||
typedef struct config_data
|
||||
{
|
||||
int32_t slider_1;
|
||||
int32_t slider_2;
|
||||
int32_t slider_3;
|
||||
int32_t slider_4;
|
||||
int32_t slider_5;
|
||||
} config_data_t;
|
||||
|
||||
typedef union config_data_u
|
||||
{
|
||||
config_data_t config;
|
||||
uint8_t data[sizeof(config_data_t)];
|
||||
} config_data_u_t;
|
||||
/* USER CODE END ET */
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#ifndef _VERSION_H
|
||||
|
||||
#define _VERSION_H
|
||||
#define VERSION_MAJOR (1u)
|
||||
#define VERSION_MINOR (1u)
|
||||
#define VERSION_PATCH (1u)
|
||||
#define VERSION_STR "V1.1.1"
|
||||
#define VERSION_MAJOR (1)
|
||||
#define VERSION_MINOR (0)
|
||||
#define VERSION_PATCH (5)
|
||||
#define VERSION_STR "V1.0.5"
|
||||
|
||||
#endif
|
198
Core/Src/NVmem.c
198
Core/Src/NVmem.c
|
@ -1,198 +0,0 @@
|
|||
/**
|
||||
*********************************************************************
|
||||
*
|
||||
* @file NVmem.c
|
||||
* @brief
|
||||
*
|
||||
* @date 2024-07-13 12:24:17
|
||||
* @author CT
|
||||
*
|
||||
* @details Provides an interface for reading and writting to non-volatile memory
|
||||
* Operates with a shadow buffer and write timeout to minimize writes to NV-memory
|
||||
*
|
||||
*************************************************************************
|
||||
**/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "stm32g4xx_hal.h"
|
||||
|
||||
#include "NVmem.h"
|
||||
|
||||
// write timeout
|
||||
static uint32_t m_last_write = 0;
|
||||
//
|
||||
static int32_t m_shadow_buf_synced = 0;
|
||||
//
|
||||
static uint8_t m_shadow_buf[NVMEM_SIZE] = {0};
|
||||
// non-volatile memory location
|
||||
uint8_t __attribute__((section (".ConfigData"))) config_data[NVMEM_SIZE] __attribute__ ((aligned (2048)));
|
||||
|
||||
|
||||
static int write_flash(void);
|
||||
static uint32_t get_bank(uint32_t addr);
|
||||
|
||||
int32_t NVmem_init(void)
|
||||
{
|
||||
// TODO add CRC over section stored at end
|
||||
// copy flash to shadow buffer
|
||||
for (uint32_t i = 0; i < NVMEM_SIZE; i++)
|
||||
{
|
||||
m_shadow_buf[i] = config_data[i];
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void NVmem_service(void)
|
||||
{
|
||||
// if the write timeout has expried and the shadow buffer has not been synced to NVmem
|
||||
if (((HAL_GetTick() - m_last_write) >= WRITE_TIMEOUT) && (!m_shadow_buf_synced))
|
||||
{
|
||||
// write shadow buffer to nvmem
|
||||
write_flash();
|
||||
|
||||
// set synced flag
|
||||
m_shadow_buf_synced = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32_t NVmem_write(uint8_t* data, uint32_t addr, uint32_t len)
|
||||
{
|
||||
// bound check
|
||||
if (addr + len >= NVMEM_SIZE)
|
||||
return (-1);
|
||||
|
||||
// write data to shadow buf
|
||||
uint32_t data_index = 0;
|
||||
for (uint32_t i = addr; i < len; i++)
|
||||
{
|
||||
m_shadow_buf[i] = data[data_index++];
|
||||
}
|
||||
|
||||
// set sync flag to out of sync
|
||||
m_shadow_buf_synced = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int32_t NVmem_write_immediate(uint8_t* data, uint32_t addr, uint32_t len)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
|
||||
// bound check
|
||||
if (addr + len >= NVMEM_SIZE)
|
||||
return (-1);
|
||||
|
||||
// write data to shadow buf
|
||||
uint32_t data_index = 0;
|
||||
for (uint32_t i = addr; i < len; i++)
|
||||
{
|
||||
m_shadow_buf[i] = data[data_index++];
|
||||
}
|
||||
|
||||
// write shadow buffer to nvmem
|
||||
ret = write_flash();
|
||||
|
||||
// set synced flag
|
||||
m_shadow_buf_synced = 1;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
int32_t NVmem_read(uint8_t* data, uint32_t addr, uint32_t len)
|
||||
{
|
||||
// bound check
|
||||
if (addr + len >= NVMEM_SIZE)
|
||||
return (-1);
|
||||
|
||||
// copy data using provided pointer
|
||||
uint32_t index = 0;
|
||||
for (uint32_t i = addr; i < len; i++)
|
||||
{
|
||||
data[index++] = m_shadow_buf[i];
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* PRIVATE FUNCTIONS */
|
||||
|
||||
// Read from flash
|
||||
|
||||
|
||||
// Write to flash
|
||||
int write_flash(void)
|
||||
{
|
||||
uint32_t page_error = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
// Erase flash area
|
||||
FLASH_EraseInitTypeDef erase_init_struct;
|
||||
|
||||
erase_init_struct.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
erase_init_struct.Banks = get_bank(NVMEM_ADDR);
|
||||
erase_init_struct.Page = (NVMEM_ADDR - FLASH_BASE) / FLASH_PAGE_SIZE;
|
||||
erase_init_struct.NbPages = 1;
|
||||
|
||||
status = HAL_FLASHEx_Erase(&erase_init_struct, &page_error);
|
||||
|
||||
if (HAL_OK != status)
|
||||
{
|
||||
HAL_FLASH_Lock();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
uint64_t buf;
|
||||
|
||||
uint32_t len = NVMEM_SIZE;
|
||||
uint32_t prog_addr = NVMEM_ADDR;
|
||||
uint32_t index = 0;
|
||||
|
||||
while (len >= 8)
|
||||
{
|
||||
buf = (uint64_t)m_shadow_buf[index];
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 1] << 8);
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 2] << 16);
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 3] << 24);
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 4] << 32);
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 5] << 40);
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 6] << 48);
|
||||
buf |= ((uint64_t)m_shadow_buf[index + 7] << 56);
|
||||
|
||||
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, prog_addr, buf);
|
||||
|
||||
index += 8;
|
||||
prog_addr += 8;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
return ((int)status);
|
||||
}
|
||||
|
||||
|
||||
uint32_t get_bank(uint32_t addr)
|
||||
{
|
||||
uint32_t bank = 0;
|
||||
uint32_t val = 0;
|
||||
|
||||
val = (addr - FLASH_BASE) / FLASH_BANK_SIZE;
|
||||
|
||||
if (0 == val)
|
||||
{
|
||||
bank = FLASH_BANK_1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bank = FLASH_BANK_2;
|
||||
}
|
||||
|
||||
return (bank);
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
/**
|
||||
*********************************************************************
|
||||
*
|
||||
* @file cir_buf.c
|
||||
* @brief Circular buffer header file
|
||||
*
|
||||
* @date 2024-04-21 18:36:52
|
||||
* @author CT
|
||||
*
|
||||
* @details Provides an interface for creating and interacting with circular
|
||||
* buffers.
|
||||
*
|
||||
*************************************************************************
|
||||
**/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "cir_buf.h"
|
||||
|
||||
// The definition of our circular buffer structure is hidden from the user
|
||||
struct circular_buf_t
|
||||
{
|
||||
uint8_t* buffer;
|
||||
size_t head;
|
||||
size_t tail;
|
||||
size_t max; // of the buffer
|
||||
bool full;
|
||||
};
|
||||
|
||||
/* PRIVATE FUNCTIONS */
|
||||
static inline size_t advance_headtail_value(size_t value, size_t max)
|
||||
{
|
||||
return (value + 1) % max;
|
||||
}
|
||||
|
||||
static void advance_head_pointer(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
|
||||
if(circular_buf_full(me))
|
||||
{
|
||||
me->tail = advance_headtail_value(me->tail, me->max);
|
||||
}
|
||||
|
||||
me->head = advance_headtail_value(me->head, me->max);
|
||||
me->full = (me->head == me->tail);
|
||||
}
|
||||
|
||||
/* API FUNCTIONS */
|
||||
|
||||
cbuf_handle_t circular_buf_init(uint8_t* buffer, size_t size)
|
||||
{
|
||||
assert(buffer && size);
|
||||
|
||||
cbuf_handle_t cbuf = malloc(sizeof(circular_buf_t));
|
||||
assert(cbuf);
|
||||
|
||||
cbuf->buffer = buffer;
|
||||
cbuf->max = size;
|
||||
circular_buf_reset(cbuf);
|
||||
|
||||
assert(circular_buf_empty(cbuf));
|
||||
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
void circular_buf_free(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
free(me);
|
||||
}
|
||||
|
||||
void circular_buf_reset(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
|
||||
me->head = 0;
|
||||
me->tail = 0;
|
||||
me->full = false;
|
||||
}
|
||||
|
||||
size_t circular_buf_size(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
|
||||
size_t size = me->max;
|
||||
|
||||
if(!circular_buf_full(me))
|
||||
{
|
||||
if(me->head >= me->tail)
|
||||
{
|
||||
size = (me->head - me->tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = (me->max + me->head - me->tail);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t circular_buf_capacity(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
|
||||
return me->max;
|
||||
}
|
||||
|
||||
void circular_buf_put(cbuf_handle_t me, uint8_t data)
|
||||
{
|
||||
assert(me && me->buffer);
|
||||
|
||||
me->buffer[me->head] = data;
|
||||
|
||||
advance_head_pointer(me);
|
||||
}
|
||||
|
||||
int circular_buf_try_put(cbuf_handle_t me, uint8_t data)
|
||||
{
|
||||
int r = -1;
|
||||
|
||||
assert(me && me->buffer);
|
||||
|
||||
if(!circular_buf_full(me))
|
||||
{
|
||||
me->buffer[me->head] = data;
|
||||
advance_head_pointer(me);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int circular_buf_get(cbuf_handle_t me, uint8_t* data)
|
||||
{
|
||||
assert(me && data && me->buffer);
|
||||
|
||||
int r = -1;
|
||||
|
||||
if(!circular_buf_empty(me))
|
||||
{
|
||||
*data = me->buffer[me->tail];
|
||||
me->tail = advance_headtail_value(me->tail, me->max);
|
||||
me->full = false;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool circular_buf_empty(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
|
||||
return (!circular_buf_full(me) && (me->head == me->tail));
|
||||
}
|
||||
|
||||
bool circular_buf_full(cbuf_handle_t me)
|
||||
{
|
||||
assert(me);
|
||||
|
||||
return me->full;
|
||||
}
|
||||
|
||||
int circular_buf_peek(cbuf_handle_t me, uint8_t* data, unsigned int look_ahead_counter)
|
||||
{
|
||||
int r = -1;
|
||||
size_t pos;
|
||||
|
||||
assert(me && data && me->buffer);
|
||||
|
||||
// We can't look beyond the current buffer size
|
||||
if(circular_buf_empty(me) || look_ahead_counter > circular_buf_size(me))
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
pos = me->tail;
|
||||
for(unsigned int i = 0; i < look_ahead_counter; i++)
|
||||
{
|
||||
data[i] = me->buffer[pos];
|
||||
pos = advance_headtail_value(pos, me->max);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,420 +0,0 @@
|
|||
/**
|
||||
*********************************************************************
|
||||
*
|
||||
* @file console.c
|
||||
* @brief
|
||||
*
|
||||
* @date 2024-04-14 19:12:40
|
||||
* @author CT
|
||||
*
|
||||
* @details
|
||||
*
|
||||
*************************************************************************
|
||||
**/
|
||||
|
||||
/*
|
||||
Operational Concept:
|
||||
Sending enter displays the current menu
|
||||
Simple 1 char command interface
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "console.h"
|
||||
#include "NVmem.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "usbd_cdc_if.h"
|
||||
|
||||
|
||||
#define CONSOLE_BUF_SIZE (256u)
|
||||
|
||||
|
||||
static cbuf_handle_t m_console_input;
|
||||
static cbuf_handle_t m_console_output;
|
||||
static uint8_t m_console_input_buf[CONSOLE_BUF_SIZE] = {0};
|
||||
static uint8_t m_console_output_buf[CONSOLE_BUF_SIZE] = {0};
|
||||
static uint8_t tx_buf[CONSOLE_BUF_SIZE];
|
||||
static uint8_t m_command_buf[16] = {0};
|
||||
static uint8_t m_command_len = 0;
|
||||
static bool m_command_ready = false;
|
||||
static bool m_echo_console = false;
|
||||
|
||||
config_data_u_t* configuration_data;
|
||||
|
||||
enum console_menu_state{main_menu, slider_1_menu, slider_2_menu, slider_3_menu, slider_4_menu, save_menu, version_menu};
|
||||
enum console_menu_state console_menu = main_menu;
|
||||
|
||||
|
||||
static void process_incoming(void);
|
||||
static void process_outgoing(void);
|
||||
static void process_command(void);
|
||||
static int console_send(uint8_t* buf, uint32_t len);
|
||||
static void menu_state_machine(void);
|
||||
static int parse_input(int32_t* data);
|
||||
static int32_t read_line(uint8_t data);
|
||||
|
||||
// menus
|
||||
static void print_main_menu(void);
|
||||
static void print_slider_menu(uint32_t slider);
|
||||
static void print_saved_menu(int32_t val);
|
||||
|
||||
// console control
|
||||
static void set_console_reset(void);
|
||||
static void set_console_red(void);
|
||||
static void set_console_green(void);
|
||||
static void reset_console(void);
|
||||
|
||||
|
||||
/* PUBLIC FUNCTIONS */
|
||||
|
||||
void console_init(config_data_u_t* config_data)
|
||||
{
|
||||
configuration_data = config_data;
|
||||
|
||||
m_console_input = circular_buf_init(m_console_input_buf, CONSOLE_BUF_SIZE);
|
||||
m_console_output = circular_buf_init(m_console_output_buf, CONSOLE_BUF_SIZE);
|
||||
}
|
||||
|
||||
|
||||
void console_service(void)
|
||||
{
|
||||
// if there is received data waiting
|
||||
process_incoming();
|
||||
|
||||
// if there is data waiting to be transmitted
|
||||
process_outgoing();
|
||||
|
||||
// Process command
|
||||
process_command();
|
||||
}
|
||||
|
||||
|
||||
/// @brief Attempts to push one byte into the console input buffer
|
||||
/// @param data byte to be pushed to input
|
||||
/// @return 0 on success, -1 on failure
|
||||
int console_push(uint8_t data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = circular_buf_try_put(m_console_input, data);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
/* PRIVATE FUNCTIONS */
|
||||
|
||||
void process_incoming(void)
|
||||
{
|
||||
if (!circular_buf_empty(m_console_input))
|
||||
{
|
||||
uint8_t data;
|
||||
while (!circular_buf_empty(m_console_input))
|
||||
{
|
||||
circular_buf_get(m_console_input, &data);
|
||||
m_command_ready = read_line(data);
|
||||
|
||||
if (m_echo_console)
|
||||
{
|
||||
circular_buf_try_put(m_console_output, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_outgoing(void)
|
||||
{
|
||||
if(!circular_buf_empty(m_console_output))
|
||||
{
|
||||
size_t tx_len = circular_buf_size(m_console_output);
|
||||
for (uint32_t i = 0; i < tx_len; i++)
|
||||
{
|
||||
circular_buf_get(m_console_output, &tx_buf[i]);
|
||||
}
|
||||
// Note: directly interacts with interface
|
||||
CDC_Transmit_FS(tx_buf, tx_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void process_command(void)
|
||||
{
|
||||
if(m_command_ready)
|
||||
{
|
||||
m_command_ready = false;
|
||||
|
||||
menu_state_machine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int console_send(uint8_t* buf, uint32_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
ret |= circular_buf_try_put(m_console_output, buf[i]);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
/// @brief Reads in a line terminated by \\n
|
||||
/// @param data
|
||||
/// @return 1 if EOL found, 0 otherwise
|
||||
int32_t read_line(uint8_t data)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
static uint8_t m_command_buf_index = 0;
|
||||
|
||||
// if EOL, return on and set length
|
||||
if((data == '\n') || (data == '\r'))
|
||||
{
|
||||
m_command_buf[m_command_buf_index++] = '\n';
|
||||
// set length of command for use within rest of module
|
||||
m_command_len = m_command_buf_index;
|
||||
// reset index
|
||||
m_command_buf_index = 0;
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
else if (data == 0x1B) // ESCAPE
|
||||
{
|
||||
m_command_len = 1;
|
||||
m_command_buf[0] = 0x1B;
|
||||
// reset index
|
||||
m_command_buf_index = 0;
|
||||
ret = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_command_buf_index < 16)
|
||||
{
|
||||
m_command_buf[m_command_buf_index++] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_command_buf_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
// Called when a complete line has been received
|
||||
void menu_state_machine(void)
|
||||
{
|
||||
int32_t success = 1;
|
||||
|
||||
switch (console_menu)
|
||||
{
|
||||
case main_menu:
|
||||
if (m_command_buf[0] == '1')
|
||||
{
|
||||
print_slider_menu(1);
|
||||
console_menu = slider_1_menu;
|
||||
}
|
||||
else if (m_command_buf[0] == '2')
|
||||
{
|
||||
print_slider_menu(2);
|
||||
console_menu = slider_2_menu;
|
||||
}
|
||||
else if (m_command_buf[0] == '3')
|
||||
{
|
||||
print_slider_menu(3);
|
||||
console_menu = slider_3_menu;
|
||||
}
|
||||
else if (m_command_buf[0] == '4')
|
||||
{
|
||||
print_slider_menu(4);
|
||||
console_menu = slider_4_menu;
|
||||
}
|
||||
else if (m_command_buf[0] == 'S')
|
||||
{
|
||||
success = NVmem_write_immediate(configuration_data->data, 0, sizeof(config_data_t));
|
||||
print_saved_menu(success);
|
||||
// need to call service because we are blocking all normal execution here
|
||||
process_outgoing();
|
||||
|
||||
// Delay for user to read result
|
||||
HAL_Delay(3000);
|
||||
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
else
|
||||
{
|
||||
print_main_menu();
|
||||
}
|
||||
break;
|
||||
case slider_1_menu:
|
||||
if (m_command_buf[0] == 0x1B) // ESCAPE
|
||||
{
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take input and immediately return to main menu
|
||||
parse_input(&configuration_data->config.slider_1);
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
break;
|
||||
|
||||
case slider_2_menu:
|
||||
if (m_command_buf[0] == 0x1B) // ESCAPE
|
||||
{
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take input and immediately return to main menu
|
||||
parse_input(&configuration_data->config.slider_2);
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
break;
|
||||
|
||||
case slider_3_menu:
|
||||
if (m_command_buf[0] == 0x1B) // ESCAPE
|
||||
{
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take input and immediately return to main menu
|
||||
parse_input(&configuration_data->config.slider_3);
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
break;
|
||||
|
||||
case slider_4_menu:
|
||||
if (m_command_buf[0] == 0x1B) // ESCAPE
|
||||
{
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take input and immediately return to main menu
|
||||
parse_input(&configuration_data->config.slider_4);
|
||||
console_menu = main_menu;
|
||||
print_main_menu();
|
||||
}
|
||||
break;
|
||||
|
||||
case save_menu:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief Parses line for integer
|
||||
/// @param data parsed out integer
|
||||
/// @return 1 on success, otherwise fail...kinda
|
||||
int parse_input(int32_t* data)
|
||||
{
|
||||
// TODO check and limit input within bounds
|
||||
// *data = atoi((char*)m_command_buf);
|
||||
int ret = sscanf((char*)m_command_buf, "%ld", data);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
// Also acts as initialization for state
|
||||
void print_main_menu(void)
|
||||
{
|
||||
char buf[256];
|
||||
|
||||
m_echo_console = true;
|
||||
|
||||
reset_console();
|
||||
set_console_red();
|
||||
|
||||
uint32_t len = snprintf(buf, 256, "Main Menu:\r\nSlider [1]: \"%li\"\r\nSlider [2]: \"%li\"\r\nSlider [3]: \"%li\"\r\nSlider [4]: \"%li\"\r\n[S]ave\r\nVersion: %s\r\nEnter Selection: ",
|
||||
configuration_data->config.slider_1, configuration_data->config.slider_2, configuration_data->config.slider_3, configuration_data->config.slider_4, VERSION_STR);
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
void print_slider_menu(uint32_t slider)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
m_echo_console = true;
|
||||
|
||||
reset_console();
|
||||
set_console_reset();
|
||||
|
||||
uint32_t len = snprintf(buf, 128, "Slider %lu Max Value (0-100): ", slider);
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
void print_saved_menu(int32_t val)
|
||||
{
|
||||
char buf[128];
|
||||
uint32_t len;
|
||||
|
||||
reset_console();
|
||||
set_console_green();
|
||||
|
||||
if (0 == val)
|
||||
{
|
||||
len = snprintf(buf, 128, "SAVED!!1!");
|
||||
}
|
||||
else
|
||||
{
|
||||
len = snprintf(buf, 128, "SAVE FAILED!");
|
||||
}
|
||||
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_console_reset(void)
|
||||
{
|
||||
char buf[16] = {0};
|
||||
uint32_t len = snprintf(buf, 16, "\x1b[1;0m");
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
void set_console_red(void)
|
||||
{
|
||||
char buf[16] = {0};
|
||||
uint32_t len = snprintf(buf, 16, "\x1b[1;31m");
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
void set_console_green(void)
|
||||
{
|
||||
char buf[16] = {0};
|
||||
uint32_t len = snprintf(buf, 16, "\x1b[1;32m");
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
||||
|
||||
|
||||
void reset_console(void)
|
||||
{
|
||||
char buf[16] = {0};
|
||||
|
||||
uint32_t len = snprintf(buf, 16, "\x1b[2J\x1b[H");
|
||||
console_send((uint8_t*)buf, len);
|
||||
}
|
|
@ -29,9 +29,6 @@
|
|||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "NVmem.h"
|
||||
#include "usbd_cdc_if.h"
|
||||
#include "version.h"
|
||||
/* USER CODE END Includes */
|
||||
|
@ -55,6 +52,7 @@ typedef struct EMA_Filter
|
|||
#define PWM_LIMIT (0.5f)
|
||||
|
||||
#define BTN_POLL_TIME (100u)
|
||||
#define UART_LOOP_TIME (1000u)
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
|
@ -76,9 +74,7 @@ float m_sliders[NUM_SLIDERS];
|
|||
|
||||
uint8_t m_buttons = 0;
|
||||
|
||||
// char buf[512] = {0};
|
||||
|
||||
config_data_u_t pwm_limit;
|
||||
char buf[512] = {0};
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
|
@ -111,6 +107,7 @@ int main(void)
|
|||
{
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
uint32_t prev_uart_tick = UART_LOOP_TIME;
|
||||
uint32_t prev_btn_time = BTN_POLL_TIME;
|
||||
/* USER CODE END 1 */
|
||||
|
||||
|
@ -143,12 +140,8 @@ int main(void)
|
|||
MX_USB_Device_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
NVmem_init();
|
||||
// Load configuration data from NV-memory
|
||||
NVmem_read(pwm_limit.data, 0, sizeof(config_data_t));
|
||||
|
||||
// Initialize the console and pass a pointer to our configuration data location
|
||||
console_init(&pwm_limit);
|
||||
// int len = snprintf(buf, 128, "Version: %s\r\n", VERSION_STR);
|
||||
// CDC_Transmit_FS((uint8_t *)buf, len);
|
||||
|
||||
// Initialize EMA filters
|
||||
for (uint32_t i = 0; i < NUM_SLIDERS; i++)
|
||||
|
@ -190,12 +183,6 @@ int main(void)
|
|||
/* USER CODE BEGIN WHILE */
|
||||
while (1)
|
||||
{
|
||||
// Service the console, not interrupt based
|
||||
console_service();
|
||||
|
||||
// Service the NVmem module
|
||||
NVmem_service();
|
||||
|
||||
if ((m_adc1_filtered_ready) == true && (m_adc2_filtered_ready == true))
|
||||
{
|
||||
// Map ADC value to PWM value
|
||||
|
@ -216,6 +203,20 @@ int main(void)
|
|||
m_adc2_filtered_ready = false;
|
||||
}
|
||||
|
||||
// if ((HAL_GetTick() - prev_uart_tick) >= UART_LOOP_TIME)
|
||||
// {
|
||||
// prev_uart_tick = HAL_GetTick();
|
||||
|
||||
// int len = snprintf(buf, 512, "Master\tCh1\tCh2\tCh3\tCh4\t\r\n");
|
||||
|
||||
// len += snprintf((buf + len), (512 - len), "%03.1f\t%03.1f\t%03.1f\t%03.1f\t%03.1f\t\r\n",
|
||||
// m_sliders[0], m_sliders[1], m_sliders[2], m_sliders[3], m_sliders[4]);
|
||||
|
||||
// len += snprintf((buf + len), (512 - len), "Version: %s\r\n", VERSION_STR);
|
||||
|
||||
// CDC_Transmit_FS((uint8_t *)buf, len);
|
||||
// }
|
||||
|
||||
if ((HAL_GetTick() - prev_btn_time) >= BTN_POLL_TIME)
|
||||
{
|
||||
prev_btn_time = HAL_GetTick();
|
||||
|
@ -331,10 +332,10 @@ void filter_adc2(void)
|
|||
*/
|
||||
void set_pwm_outputs(void)
|
||||
{
|
||||
float ch1 = map_clamp(m_sliders[1], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * pwm_limit.config.slider_1) / 100.0f));
|
||||
float ch2 = map_clamp(m_sliders[2], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * pwm_limit.config.slider_2) / 100.0f));
|
||||
float ch3 = map_clamp(m_sliders[3], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * pwm_limit.config.slider_3) / 100.0f));
|
||||
float ch4 = map_clamp(m_sliders[4], 0.0f, 100.0f, 0, ((MAX_PWM_VALUE * pwm_limit.config.slider_4) / 100.0f));
|
||||
float ch1 = map_clamp(m_sliders[1], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
|
||||
float ch2 = map_clamp(m_sliders[2], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
|
||||
float ch3 = map_clamp(m_sliders[3], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
|
||||
float ch4 = map_clamp(m_sliders[4], 0.0f, 100.0f, 0, (MAX_PWM_VALUE * PWM_LIMIT));
|
||||
|
||||
htim1.Instance->CCR1 = (uint32_t)(ch1);
|
||||
htim1.Instance->CCR2 = (uint32_t)(ch2);
|
||||
|
|
26
README.md
26
README.md
|
@ -4,7 +4,7 @@ Software for the Sliders McGee project
|
|||
|
||||
## Header Pinout
|
||||
|
||||
![Board header description](readme_assets/Slides_McGee_Pinout.png)
|
||||
![Board header description](Slides_McGee_Pinout.png)
|
||||
|
||||
## Bootloading Procedure
|
||||
|
||||
|
@ -16,27 +16,5 @@ Procedure:
|
|||
- Connect USB cable to board and computer
|
||||
- Board will present itself as a mass storage drive
|
||||
- Drag and drop new firmware image onto drive
|
||||
- Wait aproximately 10s, no progress will be indicated
|
||||
- Wait, no progress will be indicated
|
||||
- When bootloading is complete, board will launch application and drive will no longer be present on host computer
|
||||
- Removed wire jumper
|
||||
|
||||
## Building This Project
|
||||
|
||||
### Prerequisites
|
||||
|
||||
VSCode
|
||||
|
||||
STM32CubeCLT [here](https://www.st.com/en/development-tools/stm32cubeclt.html)
|
||||
|
||||
VSCode STM32 Extention
|
||||
|
||||
Once the prerequisites are installed, open VSCode and open the folder containing the project repo.
|
||||
- On the left side, click the STM32 extention and select "Import CMake project". In the dialog box that opens, select the project root foler and acept the dialog box.
|
||||
- CMake will do its CMake stuff and ask if the options are correct. The dafualts should be sufficient, click the bottom option to accept the parameters. Now you should see a build gear on the bottom toolbar with the text "Build".
|
||||
- Click the build button. The newly cloned repo will buuld without error and there will be a SW.hex file in the build folder.
|
||||
|
||||
## Console
|
||||
|
||||
The console is used to set the maximum PWM values for each slider output and saving the values to non-volatile memory. Option selections are defined by [ ] around the expected input. Inputs not recognized are ignored. Esc is used to back out of a sub-menu without modifiying the value.
|
||||
|
||||
When first connecting, press enter to display the main menu. The current values are displayed next to the slider label.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -55,26 +55,19 @@ ENTRY(Reset_Handler)
|
|||
/* Highest address of the user mode stack */
|
||||
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
|
||||
/* Generate a link error if heap and stack don't fit into RAM */
|
||||
_Min_Heap_Size = 0x400; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x800; /* required amount of stack */
|
||||
_Min_Heap_Size = 0x200; /* required amount of heap */
|
||||
_Min_Stack_Size = 0x400; /* required amount of stack */
|
||||
|
||||
/* Specify the memory areas */
|
||||
MEMORY
|
||||
{
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
FLASH (rx) : ORIGIN = 0x8010000, LENGTH = 256K
|
||||
CONFIG (r) : ORIGIN = 0x8050000, LENGTH = 2K
|
||||
}
|
||||
|
||||
/* Define output sections */
|
||||
SECTIONS
|
||||
{
|
||||
/* Application NV configuration data */
|
||||
.ConfigData (NOLOAD) :
|
||||
{
|
||||
KEEP(*(.ConfigData))
|
||||
} >CONFIG
|
||||
|
||||
/* The startup code goes first into FLASH */
|
||||
.isr_vector :
|
||||
{
|
||||
|
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 236 KiB |
|
@ -22,7 +22,7 @@
|
|||
#include "usbd_cdc_if.h"
|
||||
|
||||
/* USER CODE BEGIN INCLUDE */
|
||||
#include "console.h"
|
||||
|
||||
/* USER CODE END INCLUDE */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
|
@ -263,12 +263,6 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
|
|||
/* USER CODE BEGIN 6 */
|
||||
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
|
||||
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
|
||||
|
||||
for (uint32_t i = 0; i < *Len; i++)
|
||||
{
|
||||
console_push(Buf[i]);
|
||||
}
|
||||
|
||||
return (USBD_OK);
|
||||
/* USER CODE END 6 */
|
||||
}
|
||||
|
|
|
@ -32,9 +32,6 @@ target_sources(stm32cubemx INTERFACE
|
|||
../../Core/Src/i2c.c
|
||||
../../Core/Src/tim.c
|
||||
../../Core/Src/usart.c
|
||||
../../Core/Src/cir_buf.c
|
||||
../../Core/Src/console.c
|
||||
../../Core/Src/NVmem.c
|
||||
../../Core/Src/stm32g4xx_it.c
|
||||
../../Core/Src/stm32g4xx_hal_msp.c
|
||||
../../USB_Device/Target/usbd_conf.c
|
||||
|
|
Loading…
Reference in New Issue
Block a user