initial commit of in progress firmware

nearly everything is "implemented" but how well it works, or if it works at all, is unknown.
This commit is contained in:
true
2024-10-16 23:51:49 -07:00
commit 078f382dcc
69 changed files with 25810 additions and 0 deletions

106
gat_stand_fw/user/src/btn.c Normal file
View File

@@ -0,0 +1,106 @@
/*
* btn.c
*
* handles buttons as well as the
* DIP switches (in case action is desired by hot-switching)
*/
#include <ch32v20x.h>
#include "btn.h"
struct Btn btn[BTN_COUNT] = {0};
void btn_init()
{
uint8_t i;
// this function assumes GPIO has been configured already
// initialize default setup
btn[0]._pintype = BTN1_PIN;
btn[1]._pintype = BTN2_PIN;
btn[2]._pintype = DIP1_PIN;
btn[3]._pintype = DIP2_PIN;
btn[4]._pintype = DIP3_PIN;
for (i = 0; i < BTN_COUNT; i++) {
btn[i]._mask = BTN_RELEASE;
// ignore any currently pressed buttons
if (!(BTN_PORT->INDR & (1 << (btn[i]._pintype & BTN_PIN_MASK)))) {
btn[0]._mask |= BTN_IGNORE;
}
}
}
void btn_poll()
{
uint8_t i;
uint8_t r;
uint8_t ignore;
uint8_t pushed;
for (i = 0; i < BTN_COUNT; i++) {
pushed = 0;
ignore = btn[i]._mask & BTN_IGNORE;
r = BTN_PORT->INDR & (1 << (btn[i]._pintype & BTN_PIN_MASK));
// active low type buttons
if (!r) pushed = 1;
if (pushed) {
// hold counter
if (btn[i]._count < 0xffff) btn[i]._count++;
// pushed long enough?
if (btn[i]._count < BTN_DEBOUNCE) continue;
// first push?
if (!(btn[i]._mask & BTN_PUSH)) {
btn[i]._mask = BTN_PUSH | ignore;
if (btn[i].cb_push && !ignore) {
btn[i].cb_push(i);
btn[i]._mask |= (BTN_PUSH << 4);
}
} else if (btn[i]._count >= btn[i].hold) {
// held to count limit
// if button is not repeatable, do not retrigger
if ((btn[i]._mask & BTN_HOLD) && !btn[i].repeat) continue;
btn[i]._mask |= BTN_HOLD;
// call callback only if not in ignore state
if (btn[i].cb_hold && !ignore) {
btn[i].cb_hold(i);
btn[i]._mask |= (BTN_HOLD << 4);
}
// apply repeat rate to count
if (btn[i].repeat > btn[i]._count) {
btn[i]._count = 0;
} else btn[i]._count -= btn[i].repeat;
}
} else {
// is not pushed
if (!(btn[i]._mask & BTN_RELEASE)) {
// note: release will remove ignore status
btn[i]._mask = BTN_RELEASE;
btn[i]._count = 0;
// call callback only if not in ignore state
if (btn[i].cb_release && !ignore) {
btn[i].cb_release(i);
btn[i]._mask |= (BTN_RELEASE << 4);
}
}
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* btn.h
*/
#ifndef USER_SRC_BTN_H_
#define USER_SRC_BTN_H_
#include <ch32v20x.h>
#define BTN_COUNT 5
#define BTN_DEBOUNCE (24 / 4) // debounce time in ~4ms increments
#define BTN_PORT GPIOB
#define BTN1_PIN 10
#define BTN2_PIN 11
#define DIP1_PIN 12
#define DIP2_PIN 13
#define DIP3_PIN 14
#define BTN_PIN_MASK 0xf
#define BTN_PUSH (1 << 0)
#define BTN_HOLD (1 << 1)
#define BTN_RELEASE (1 << 2)
#define BTN_IGNORE (1 << 3)
typedef struct Btn {
uint8_t _pintype;
uint8_t _mask;
uint16_t _count; // held counts
uint16_t hold; // initial hold
uint16_t repeat; // repeated hold
void (*cb_push)(uint8_t);
void (*cb_hold)(uint8_t);
void (*cb_release)(uint8_t);
} Btn;
extern struct Btn btn[BTN_COUNT];
void btn_init();
void btn_poll();
#endif /* USER_SRC_BTN_H_ */

View File

@@ -0,0 +1,24 @@
/*
* gat_gpio.c
*
* Created on: Oct 16, 2024
* Author: true
*/
#include "gat_gpio.h"
static GPIO_InitTypeDef gpio;
void gat_gpio_init()
{
// set the ID to 0 on GP pins.
gpio.GPIO_Speed = GPIO_Speed_2MHz;
gpio.GPIO_Mode = GPIO_Mode_IPD;
gpio.GPIO_Pin = (1 << GAT_GP1_PIN) | (1 << GAT_GP2_PIN);
GPIO_Init(GAT_GPIO_PORT, &gpio);
}

View File

@@ -0,0 +1,28 @@
/*
* gat_gpio.h
*
* Created on: Oct 16, 2024
* Author: true
*/
#ifndef USER_SRC_GAT_GPIO_H_
#define USER_SRC_GAT_GPIO_H_
#include <ch32v20x.h>
#define GAT_GPIO_PORT GPIOA
#define GAT_GP1_PIN 9
#define GAT_GP2_PIN 10
void gat_gpio_init();
#endif /* USER_SRC_GAT_GPIO_H_ */

View File

@@ -0,0 +1,103 @@
/*
* port_pwr.c
*
* Created Oct 16, 2024
*
* power control for GAT and USB ports.
*/
#include <ch32v20x.h>
#include "port_pwr.h"
#define PORT_PWR_STATE_DR BKP_DR3
#define GAT_ON_FLAG (1 << 0)
#define USB2_ON_FLAG (1 << 1)
#define INIT_FLAG (0xa0 << 8)
static uint8_t port_pwr_state;
static uint8_t gat_oc_state_latch = 0;
void gat_on()
{
if (gat_oc_state_latch) return;
GAT_EN_PORT->BSHR = GAT_EN_PIN;
port_pwr_state |= GAT_ON_FLAG;
BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state);
}
void gat_off()
{
GAT_EN_PORT->BCR = GAT_EN_PIN;
port_pwr_state &= ~GAT_ON_FLAG;
BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state);
}
uint8_t gat_pwr_state()
{
return (GAT_EN_PORT->OUTDR & GAT_EN_PIN) ? 1 : 0;
}
uint8_t gat_oc_state()
{
if (!(GAT_OC_PORT->INDR & GAT_OC_PIN)) {
gat_oc_state_latch = 1;
gat_off();
}
return gat_oc_state_latch;
}
void gat_toggle()
{
if (gat_pwr_state()) gat_off();
else gat_on();
}
void usb2_on()
{
port_pwr_state |= USB2_ON_FLAG;
BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state);
}
void usb2_off()
{
port_pwr_state &= ~USB2_ON_FLAG;
BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state);
}
uint8_t usb2_pwr_state()
{
return (USB2_EN_PORT->OUTDR & USB2_EN_PIN) ? 1 : 0;
}
void usb2_toggle()
{
if (usb2_pwr_state()) gat_off();
else gat_on();
}
void port_pwr_init()
{
port_pwr_state = BKP_ReadBackupRegister(PORT_PWR_STATE_DR);
if ((port_pwr_state & INIT_FLAG) != INIT_FLAG) {
// no battery retention.
// automatically turn on all outputs
port_pwr_state |= INIT_FLAG;
gat_on();
usb2_on();
}
}

View File

@@ -0,0 +1,46 @@
/*
* port_pwr.h
*
* Created on: Oct 16, 2024
* Author: true
*/
#ifndef USER_SRC_PORT_PWR_H_
#define USER_SRC_PORT_PWR_H_
#include <ch32v20x.h>
// GAT port enable pin
#define GAT_EN_PORT GPIOA
#define GAT_EN_PIN GPIO_Pin_3
// overcurrent detect pin, active low
#define GAT_OC_PORT GPIOA
#define GAT_OC_PIN GPIO_Pin_4
#define USB2_EN_PORT GPIOB
#define USB2_EN_PIN GPIO_Pin_4
void port_pwr_init();
uint8_t gat_oc_state();
void gat_on();
void gat_off();
void gat_toggle();
uint8_t gat_pwr_state();
void usb2_on();
void usb2_off();
void usb2_toggle();
uint8_t usb2_pwr_state();
#endif /* USER_SRC_PORT_PWR_H_ */

View File

@@ -0,0 +1,119 @@
/*
* rgbled.c
*
* using TIM2 CH1-CH3
*/
#include <ch32v20x.h>
#include <stdint.h>
#include "rtc.h"
#include "port_pwr.h"
#define RED 0
#define GRN 1
#define BLU 2
#define BRT_RED 200
#define BRT_GRN 100
#define BRT_BLU 200
#define RGBLED_TIM TIM2
static uint8_t flash_timeout[3];
static uint8_t flash[3] = {0};
static uint8_t state[3] = {0};
void rgbled_set()
{
uint8_t i;
// flash counters
for (i = 0; i < 3; i++) {
if (!flash[i]) {
flash[i] = flash_timeout[i];
} else flash[i]--;
switch (flash_timeout[i]) {
// always on
case 0x00: {
state[i] = 1;
break;
}
// always off
case 0xff: {
state[i] = 0;
break;
}
// standard
default: {
if (flash[i] == flash_timeout[i]) {
state[i] ^= 1;
}
}
}
}
RGBLED_TIM->CH1CVR = state[RED] ? BRT_RED : 0;
RGBLED_TIM->CH2CVR = state[GRN] ? BRT_GRN : 0;
RGBLED_TIM->CH3CVR = state[BLU] ? BRT_BLU : 0;
}
void rgbled_update()
{
uint16_t w;
// VCR flash if clock isn't set
w = BKP_ReadBackupRegister(RTC_STATE_DR);
switch (w) {
case RTC_STATE_UNINITIALIZED: {
flash_timeout[BLU] = 254;
break;
}
default: {
flash_timeout[BLU] = 0;
break;
}
}
flash_timeout[GRN] = gat_pwr_state() ? 0 : 0xff;
flash_timeout[RED] = gat_oc_state() ? 50 : 0xff;
}
void rgbled_init()
{
TIM_TimeBaseInitTypeDef timer ={0};
TIM_OCInitTypeDef pwm = {0};
timer.TIM_Period = (1 << 10) - 1; // 10-bit
timer.TIM_Prescaler = 0;
timer.TIM_ClockDivision = TIM_CKD_DIV1;
timer.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(RGBLED_TIM, &timer);
pwm.TIM_OCMode = TIM_OCMode_PWM1;
pwm.TIM_OutputState = TIM_OutputState_Enable;
pwm.TIM_Pulse = 0;
pwm.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(RGBLED_TIM, &pwm);
TIM_OC2Init(RGBLED_TIM, &pwm);
TIM_OC3Init(RGBLED_TIM, &pwm);
TIM_CtrlPWMOutputs(RGBLED_TIM, ENABLE);
TIM_OC1PreloadConfig(RGBLED_TIM, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(RGBLED_TIM, ENABLE);
TIM_Cmd(RGBLED_TIM, ENABLE);
RGBLED_TIM->CH1CVR = 0;
RGBLED_TIM->CH2CVR = 0;
RGBLED_TIM->CH3CVR = 0;
}

View File

@@ -0,0 +1,24 @@
/*
* rgbled.h
*
* Created on: Oct 16, 2024
* Author: true
*/
#ifndef USER_SRC_RGBLED_H_
#define USER_SRC_RGBLED_H_
#define RGBLED_PORT GPIOA
#define RGBLED_PIN_R GPIO_Pin_0
#define RGBLED_PIN_G GPIO_Pin_1
#define RGBLED_PIN_B GPIO_Pin_2
void rgbled_update();
#endif /* USER_SRC_RGBLED_H_ */

160
gat_stand_fw/user/src/rtc.c Normal file
View File

@@ -0,0 +1,160 @@
/*
* rtc.c
*
* Created on: Oct 16, 2024
* Author: true
*/
#include <ch32v20x.h>
#include <stdint.h>
#include "rtc.h"
#define RTC_INIT_PATTERN 0x1337
static const uint8_t days_per_mon[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
uint8_t rtc_state;
void rtc_set_state(uint16_t state)
{
rtc_state = state;
}
/*
* @fn rtc_is_leapyear
* @brief Returns true if year is a leap year.
*
* @param year
*
* @return 1 - Yes
* 0 - No
*/
uint8_t rtc_is_leapyear(u16 year)
{
if (year % 4 == 0) {
if (year % 100 == 0) {
if (year % 400 == 0) {
return 1;
} else {
return 0;
}
}
else return 1;
}
else return 0;
}
/*
* @fn rtc_set_clock
* @brief Set Time.
*
* @param Struct of RTClock
*
* @return 1 - error
* 0 - success
*/
int8_t rtc_set_clock(struct RTClock *c)
{
uint16_t x;
uint8_t m;
uint32_t count = 0;
if(c->year < 1970 || c->year > 2099)
return -1;
for(x = 1970; x < c->year; x++) {
if (rtc_is_leapyear(x))
count += 31622400;
else
count += 31536000;
}
m = c->mon - 1;
for(x = 0; x < m; x++){
count += (u32)days_per_mon[x] * 86400;
if(rtc_is_leapyear(c->year) && x == 1)
count += 86400;
}
count += (u32)(c->day - 1) * 86400;
count += (u32)c->h * 3600;
count += (u32)c->m * 60;
count += c->s;
PWR_BackupAccessCmd(ENABLE);
RTC_SetCounter(count);
RTC_WaitForLastTask();
return 0;
}
int8_t rtc_init()
{
uint32_t timeout;
static const struct RTClock clock = {
.year = 2024,
.mon = 11,
.day = 1,
.h = 8,
.m = 0,
.s = 0
};
// enable access to RTC registers
PWR_BackupAccessCmd(ENABLE);
// get RTC state
// if things aren't configured it'll be initialized in a moment
rtc_state = BKP_ReadBackupRegister(RTC_STATE_DR);
// is RTC already configured?
if (BKP_ReadBackupRegister(RTC_INIT_DR) != RTC_INIT_PATTERN) {
// must not be. initialize rtc
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_ON);
timeout = SystemCoreClock / 2;
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && timeout--);
// if crystal didn't start in time, let the application know
if (!timeout) return -1;
// use crystal for RTC and enable it
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForLastTask();
RTC_WaitForSynchro();
// RTC_ITConfig(RTC_IT_ALR, ENABLE);
// RTC_ITConfig(RTC_IT_SEC, ENABLE);
// RTC_WaitForLastTask();
RTC_EnterConfigMode();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
// set an initial time
rtc_set_clock((struct RTClock *)&clock);
RTC_ExitConfigMode();
rtc_state = RTC_STATE_CLOCK_NOT_SET;
BKP_WriteBackupRegister(RTC_STATE_DR, rtc_state);
BKP_WriteBackupRegister(RTC_INIT_DR, RTC_INIT_PATTERN);
// RTC_NVIC_Config();
// RTC_Get();
}
return 0;
}

View File

@@ -0,0 +1,44 @@
/*
* rtc.h
*
* Created on: Oct 16, 2024
* Author: true
*/
#ifndef USER_SRC_RTC_H_
#define USER_SRC_RTC_H_
#include <stdint.h>
#define RTC_INIT_DR BKP_DR1
#define RTC_STATE_DR BKP_DR2
enum RTCState {
RTC_STATE_UNINITIALIZED = 0,
RTC_STATE_CLOCK_NOT_SET,
RTC_STATE_OK = 0x7f
};
typedef struct RTClock {
uint16_t year;
uint8_t mon;
uint8_t day;
uint8_t h;
uint8_t m;
uint8_t s;
} RTClock;
int8_t rtc_init();
int8_t rtc_set_clock(struct RTClock *c);
#endif /* USER_SRC_RTC_H_ */