sc8-gat-stand/gat_stand_fw/user/main.c

259 lines
6.3 KiB
C

/*
* The GAT Stand
* GAT Host Firmware
* by true
*
* version 0.0.1
*
*
* notes:
*
* - last 2K of flash memory is reserved for configuration storage
*
*
* project todo:
*
* - implement config storage
*
* - implement USB CDC command shell
*
* - when USB is not active, go into super low power state
* - light sensor is only checked once every two seconds or so
* - buttons are on wakeup
*/
#include <ch32v20x.h>
#include "periph/adc.h"
#include "periph/btn.h"
#include "periph/gat_gpio.h"
#include "periph/port_pwr.h"
#include "periph/rgbled.h"
#include "periph/rtc.h"
#include "periph/usb/cdc.h"
#include "usb_lib.h"
#include "console/console.h"
#include "../usblib/config/usb_pwr.h"
void btn_top_push_cb(uint8_t idx)
{
// jumper 3, if set, will manage power by brightness automatically
// only respect the button if this switch isn't set
if (!(btn[DIP3]._mask & BTN_PUSH)) {
gat_toggle();
}
}
void btn_bot_push_cb(uint8_t idx)
{
// jumper 3, if set, will manage power by brightness automatically
// only respect the button if this switch isn't set
if (!(btn[DIP3]._mask & BTN_PUSH)) {
usb2_toggle();
}
}
static inline void systick_init(void)
{
SysTick->CMP = (SystemCoreClock / 256) - 1; // we want a 256Hz interrupt
SysTick->CNT = 0; // clear counter
SysTick->CTLR = 0xF; // start counter in /1 mode, enable interrupts, auto-reset counter
SysTick->SR = 0; // clear count comparison flag
NVIC_EnableIRQ(SysTicK_IRQn); // enable interrupt
}
static void gpio_init()
{
GPIO_InitTypeDef gpio = {0};
gpio.GPIO_Speed = GPIO_Speed_2MHz;
// unused pins
gpio.GPIO_Mode = GPIO_Mode_IPD;
gpio.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOD, &gpio);
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_5 | GPIO_Pin_15;
GPIO_Init(GPIOB, &gpio);
// OSC32K: don't need to configure these pins from defaults
// enabling RTC does whatever is needed for these pins (assumed from example)
// RGBLED (PA0, PA1, PA2)
RGBLED_PORT->BSHR = RGBLED_PIN_R | RGBLED_PIN_G | RGBLED_PIN_B;
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = RGBLED_PIN_R | RGBLED_PIN_G | RGBLED_PIN_B;
GPIO_Init(RGBLED_PORT, &gpio);
// GAT power enable (PA3)
GAT_EN_PORT->BCR = GAT_EN_PIN;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = GAT_EN_PIN;
GPIO_Init(GAT_EN_PORT, &gpio);
// lightsense anode (PA5)
LSENS_A_PORT->BCR = LSENS_A_PIN;
gpio.GPIO_Pin = LSENS_A_PIN;
GPIO_Init(LSENS_A_PORT, &gpio);
// lightsense cathode (PB0)
LSENS_K_PORT->BCR = LSENS_K_PIN;
gpio.GPIO_Pin = LSENS_K_PIN;
GPIO_Init(LSENS_K_PORT, &gpio);
// USB2 power enable (PB4)
USB2_EN_PORT->BCR = USB2_EN_PIN;
gpio.GPIO_Pin = USB2_EN_PIN;
GPIO_Init(USB2_EN_PORT, &gpio);
// GAT overcurrent detect (PA4)
gpio.GPIO_Mode = GPIO_Mode_IPU;
gpio.GPIO_Pin = GAT_OC_PIN;
GPIO_Init(GAT_EN_PORT, &gpio);
// buttons (PB10, PB11) and DIP switches (PB12, PB13, PB14)
gpio.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;
GPIO_Init(GPIOB, &gpio);
// GAT GPIO is configured in gat_gpio.c
// USB PA11, PA12 will be configured later
// unused pins that are used for I2C passthrough
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOB, &gpio);
// USB PB6, PB7 will be configured later
// I2C (PB8, PB9) - remapped
GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
gpio.GPIO_Speed = GPIO_Speed_10MHz;
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Mode = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &gpio);
}
int main(void)
{
// configure core
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
SystemCoreClockUpdate();
// enable peripheral clocks
RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP |
RCC_APB1Periph_I2C1 | RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA |
RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD |
RCC_APB2Periph_ADC1, ENABLE);
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_USBHS, ENABLE);
// configure gpio pins
gpio_init();
// configure RTC
if (rtc_init()) {
// rtc failed to initialize. let the end user know.
// todo
}
// initialize buttons
btn_init();
btn[0].cb_push = btn_top_push_cb;
btn[1].cb_push = btn_bot_push_cb;
// set GAT GP pins weak pull to address the addon
gat_gpio_init();
// set output ports to saved state, or on if no batt / first boot
port_pwr_init();
// start up rgbled
rgbled_init();
// initialize light sense stuff
adc_init();
// get the system tick interrupt going
systick_init();
// initialize USB device for console shell
usb_conf_clksource();
USB_Init();
usb_intr_init();
// then initialize shell
console_set_gets(0);
console_set_puts(0);
console_init();
// let's do this
while (1) {
// todo: add check to see if USB is connected
if (bDeviceState == CONFIGURED) {
console_process();
} else {
console_stop();
}
__WFI();
}
}
uint8_t st_tick;
volatile uint32_t uptime;
__attribute__((interrupt("WCH-Interrupt-fast")))
void SysTick_Handler(void)
{
st_tick++;
if (!st_tick) {
uptime++;
// jumper 3, if set, will manage power by brightness automatically
if (btn[DIP3]._mask & BTN_PUSH) {
if (adc_get_lsens_coarse() > LSENS_DARK) {
gat_off();
usb2_off();
}
if (adc_get_lsens_coarse() <= LSENS_BRIGHT) {
gat_on();
usb2_on();
}
}
}
// light sensor updating at ~4ms
adc_process_lsens();
// update buttons
btn_poll();
if (!(st_tick & 0x3)) {
rgbled_update();
}
// clear comparison flag
SysTick->SR = 0;
if (SysTick->SR) {
while (1);
}
}