Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions software/firmware/board_check/src/board_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@

const uint8_t statusLEDs[] = { PIN_INIT, PIN_RDY, PIN_RUN, PIN_IDLE };
const uint8_t cols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D, PIN_COL_E };

const uint8_t inputPins[] = { PIN_INPUT_A, PIN_INPUT_B, PIN_INPUT_C, PIN_INPUT_D };
const uint8_t inputCols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D }; // TC1–TC4
typedef enum {
MODE_DEMO,
MODE_INPUT
Expand Down Expand Up @@ -62,10 +63,13 @@ void setupPins() {
funPinMode(PIN_ROW_G, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
funDigitalWrite(PIN_ROW_R, FUN_HIGH); // Start rows OFF
funDigitalWrite(PIN_ROW_G, FUN_HIGH);

for (int i = 0; i < 4; i++) {
funPinMode(inputPins[i], GPIO_CNF_IN_PUPD);
funDigitalWrite(inputPins[i], FUN_HIGH); // enable pull‑up
}

const uint8_t inputPins[] = { PIN_INPUT_A, PIN_INPUT_B, PIN_INPUT_C, PIN_INPUT_D };
const uint8_t inputCols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D }; // TC1–TC4
}

bool isAnyButtonPressed() {
for (int i = 0; i < 4; i++) {
Expand Down
47 changes: 47 additions & 0 deletions software/firmware/tester_runtime/src/buttons.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@


#include "pins.h"
#include "buttons.h"
#include <stdint.h>
#include <stdbool.h>
#include "ch32fun.h"
#include "hardware.h"
#include "globals.h"
#include "pins.h"

volatile ButtonState buttons[4];
static uint8_t lastButtonSample = 0xFF;
static uint32_t initLedOffAt = 0;

void pollButtons(void) {
uint8_t sample = 0;
for (int i = 0; i < 4; i++) {
if (!gpio_get(BTN[i].port, BTN[i].mask)) {
sample |= (1 << i);
}
}

uint8_t changed = sample ^ lastButtonSample;
if (changed) {
for (int i = 0; i < 4; i++) {
if ((changed & (1 << i)) && (sample & (1 << i))) {
buttons[i].pressed = true;
buttons[i].justPressed = true;
buttons[i].lastPressTime = msTicks;
buttons[i].pressCount++;
gpio_clear(GPIOC, BIT(6));
initLedOffAt = msTicks + 50;
} else if (changed & (1 << i)) {
buttons[i].pressed = false;
buttons[i].lastReleaseTime = msTicks;
}
}
}

if (initLedOffAt && msTicks >= initLedOffAt) {
gpio_set(GPIOC, BIT(6));
initLedOffAt = 0;
}

lastButtonSample = sample;
}
18 changes: 18 additions & 0 deletions software/firmware/tester_runtime/src/buttons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef BUTTONS_H
#define BUTTONS_H

#include <stdint.h>
#include <stdbool.h>

typedef struct {
uint32_t lastPressTime;
uint32_t lastReleaseTime;
uint16_t pressCount;
bool pressed;
bool justPressed;
} ButtonState;

extern volatile ButtonState buttons[4];
void pollButtons(void);

#endif // BUTTONS_H
1 change: 1 addition & 0 deletions software/firmware/tester_runtime/src/funconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

// you can put various configurations in here, you can see a full list in ch32fun.h
// part selection is made in the Makefile
#define FUNCONF_ENABLE_HPE 0

#endif

12 changes: 12 additions & 0 deletions software/firmware/tester_runtime/src/globals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef GLOBALS_H
#define GLOBALS_H
#include <stdint.h>
#include <stdbool.h>

extern volatile uint32_t msTicks;
extern volatile bool flashState;
extern volatile bool rapidFlashState;
extern volatile bool runMode;
extern volatile uint8_t currentCol;

#endif // GLOBALS_H
149 changes: 149 additions & 0 deletions software/firmware/tester_runtime/src/hardware.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@

#include <stdint.h>
#include <stdbool.h>
#include "ch32fun.h"
#include "pins.h"
#include "hardware.h"
#include "buttons.h"
#include "leds.h"
#include "globals.h"
#include "pins.h"

// Pin port/mask arrays/structs (define here)
const PinDef COL[5] = {
{GPIOC, 0x01}, {GPIOC, 0x02}, {GPIOC, 0x04}, {GPIOC, 0x08}, {GPIOC, 0x10}
};
const PinDef ROW_RED = { GPIOA, 0x02 };
const PinDef ROW_GREEN = { GPIOA, 0x04 };
const PinDef BTN[4] = {
{GPIOD, 0x04}, {GPIOD, 0x08}, {GPIOD, 0x10}, {GPIOD, 0x20}
};

// Global variables (define here)
volatile uint32_t msTicks = 0;
volatile bool flashState = false;
volatile bool rapidFlashState = false;
volatile bool runMode = false;
volatile uint8_t currentCol = 0;

static const int statusLEDs[] = { PIN_PWR, PIN_INIT, PIN_RDY, PIN_RUN, PIN_IDLE };
static const int testCols[] = { PIN_COL_A, PIN_COL_B, PIN_COL_C, PIN_COL_D, PIN_COL_E };
static const int inputPins[] = { PIN_INPUT_A, PIN_INPUT_B, PIN_INPUT_C, PIN_INPUT_D };

// Timer ISR for 1ms tick, button polling, and LED scan
void TIM1_UP_IRQHandler(void) INTERRUPT_DECORATOR;
void TIM1_UP_IRQHandler(void)
{
if (TIM1->INTFR & TIM_UIF) {
TIM1->INTFR &= ~TIM_UIF;
msTicks++;
pollButtons();
static uint32_t nextFlashAt = 250;
if (msTicks >= nextFlashAt) {
nextFlashAt += 250;
flashState = !flashState;
}
static uint32_t nextRapidFlashAt = 125;
if (msTicks >= nextRapidFlashAt) {
nextRapidFlashAt += 125;
rapidFlashState = !rapidFlashState;
}
scanStep();
}
}

void setupPins(void) {
funGpioInitAll();
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD;
for (int i = 0; i < 5; i++) {
funPinMode(statusLEDs[i], GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
funDigitalWrite(statusLEDs[i], FUN_HIGH);
}
for (int i = 0; i < 5; i++) {
funPinMode(testCols[i], GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
funDigitalWrite(testCols[i], FUN_LOW);
}
funPinMode(PIN_ROW_R, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
funPinMode(PIN_ROW_G, GPIO_Speed_10MHz | GPIO_CNF_OUT_PP);
funDigitalWrite(PIN_ROW_R, FUN_HIGH);
funDigitalWrite(PIN_ROW_G, FUN_HIGH);
for (int i = 0; i < 4; i++) {
funPinMode(inputPins[i], GPIO_CNF_IN_PUPD);
funDigitalWrite(inputPins[i], FUN_HIGH);
}
}

void setupStatusFlasher(void) {
RCC->APB2PCENR |= RCC_APB2Periph_TIM1;
RCC->APB2PRSTR |= RCC_APB2Periph_TIM1;
RCC->APB2PRSTR &= ~RCC_APB2Periph_TIM1;
TIM1->PSC = 48 - 1;
TIM1->ATRLR = 1000 - 1;
TIM1->SWEVGR |= TIM_UG;
TIM1->INTFR &= ~TIM_UIF;
TIM1->DMAINTENR |= TIM_UIE;
NVIC_EnableIRQ(TIM1_UP_IRQn);
TIM1->CTLR1 |= TIM_CEN;
}

void runStatus(bool isRun) {
runMode = isRun;
funDigitalWrite(PIN_RUN, FUN_HIGH);
funDigitalWrite(PIN_IDLE, FUN_HIGH);
}

void waitTicks(uint32_t ticks) {
uint32_t start = msTicks;
while ((uint32_t)(msTicks - start) < ticks) {
__WFI();
}
}

void scanStep(void) {
static int8_t prev = -1;
if (activeStates == NULL) {
gpio_set(ROW_RED.port, ROW_RED.mask);
gpio_set(ROW_GREEN.port, ROW_GREEN.mask);
return;
}
gpio_set(ROW_RED.port, ROW_RED.mask);
gpio_set(ROW_GREEN.port, ROW_GREEN.mask);
if (prev >= 0 && prev < 5) {
if (COL[prev].port != NULL) {
gpio_clear(COL[prev].port, COL[prev].mask);
}
}
if (currentCol >= 0 && currentCol < 5) {
TestCaseState state = activeStates[currentCol];
switch (state) {
case TC_PASS:
gpio_clear(ROW_GREEN.port, ROW_GREEN.mask);
break;
case TC_FAIL:
gpio_clear(ROW_RED.port, ROW_RED.mask);
break;
case TC_IN_PROGRESS:
if (flashState)
gpio_clear(ROW_RED.port, ROW_RED.mask);
else
gpio_clear(ROW_GREEN.port, ROW_GREEN.mask);
break;
case TC_WARNING:
if (flashState)
gpio_clear(ROW_RED.port, ROW_RED.mask);
break;
case TC_RETRY:
if (rapidFlashState)
gpio_clear(ROW_RED.port, ROW_RED.mask);
break;
case TC_NO_RESULT:
default:
break;
}
if (COL[currentCol].port != NULL) {
gpio_set(COL[currentCol].port, COL[currentCol].mask);
}
}
prev = currentCol;
currentCol = (currentCol + 1) % 5;
}
15 changes: 15 additions & 0 deletions software/firmware/tester_runtime/src/hardware.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef HARDWARE_H
#define HARDWARE_H

#include <stdint.h>
#include <stdbool.h>
#include "ch32fun.h"
#include "test_cases.h"

void setupPins(void);
void setupStatusFlasher(void);
void runStatus(bool isRun);
void waitTicks(uint32_t ticks);
void scanStep(void);

#endif // HARDWARE_H
66 changes: 66 additions & 0 deletions software/firmware/tester_runtime/src/leds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@



#include <stdint.h>
#include <stdbool.h>
#include "ch32fun.h"
#include "hardware.h"
#include "test_cases.h"
#include "globals.h"
#include "pins.h"

// Double-buffered states (publish by pointer swap)
static TestCaseState bufA[5], bufB[5];
volatile const TestCaseState* activeStates = bufA;
static uint8_t activeIdx = 0;



void initTestCaseStates(void) {
for (int i = 0; i < 5; i++) { bufA[i] = bufB[i] = TC_NO_RESULT; }
activeStates = bufA;
activeIdx = 0;
}

void setTestCaseResult(const TestCaseState states[5]) {
TestCaseState* dst = (activeIdx == 0) ? bufB : bufA;
for (int i = 0; i < 5; i++) dst[i] = states[i];
__disable_irq();
__asm volatile ("" ::: "memory");
activeStates = (volatile const TestCaseState*)dst;
activeIdx ^= 1;
__asm volatile ("" ::: "memory");
__enable_irq();
}

void serviceStatusLeds(void) {
static bool lastFlash = 0, lastMode = 0;
if (flashState != lastFlash || runMode != lastMode) {
uint16_t activePin = runMode ? PIN_RUN : PIN_IDLE;
uint16_t inactivePin = runMode ? PIN_IDLE : PIN_RUN;
funDigitalWrite(activePin, flashState ? FUN_LOW : FUN_HIGH);
funDigitalWrite(inactivePin, FUN_HIGH);
lastFlash = flashState;
lastMode = runMode;
}
}

void testCaseLEDStartupPattern(void) {
static TestCaseState demoStates[5];
for (int k = 0; k < 4; k++) {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
demoStates[i] = TC_PASS;
setTestCaseResult(demoStates);
waitTicks(30);
}
for (int i = 4; i >= 0; i--) {
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
demoStates[i] = TC_FAIL;
setTestCaseResult(demoStates);
waitTicks(30);
}
}
for (int j = 0; j < 5; j++) demoStates[j] = TC_NO_RESULT;
setTestCaseResult(demoStates);
}
19 changes: 19 additions & 0 deletions software/firmware/tester_runtime/src/leds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stdint.h>
#include "test_cases.h"

extern volatile const TestCaseState* activeStates;
#ifndef LEDS_H
#define LEDS_H

#include <stdint.h>
#include <stdbool.h>


#include "test_cases.h"

void serviceStatusLeds(void);
void setTestCaseResult(const TestCaseState states[5]);
void initTestCaseStates(void);
void testCaseLEDStartupPattern(void);

#endif // LEDS_H
Loading
Loading