aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDien-Nhung Nguyen-Phu <kein@kienlab.com>2024-05-19 16:22:51 +0700
committerDien-Nhung Nguyen-Phu <kein@kienlab.com>2024-06-03 11:48:18 +0700
commit90cdb61063b408aa4d8ba0c1e3c36d804f69f61a (patch)
treeccfe2db3861197bc29eff52e53a814d909501863 /src
parent7d7389cac55952fcb794d2632747a8adc1e119ee (diff)
led: add basic Charlieplexing scan
Diffstat (limited to 'src')
-rw-r--r--src/leddrv.c150
-rw-r--r--src/leddrv.h14
-rw-r--r--src/main.c86
3 files changed, 236 insertions, 14 deletions
diff --git a/src/leddrv.c b/src/leddrv.c
new file mode 100644
index 0000000..9eeba05
--- /dev/null
+++ b/src/leddrv.c
@@ -0,0 +1,150 @@
+#include "leddrv.h"
+
+#define LED_DRIVE_STRENTH 0
+#define LED_PINCOUNT (23)
+typedef enum {
+ FLOATING,
+ LOW,
+ HIGH,
+} tristate_t;
+
+typedef struct {
+ uint32_t *port_buf;
+ uint32_t *cfg_buf;
+ uint32_t pin;
+} pinctrl_t;
+
+static void gpio_buf_set(pinctrl_t pinctl, tristate_t state)
+{
+ if (state == FLOATING) {
+ *(pinctl.cfg_buf) &= ~pinctl.pin;
+ } else {
+ if (state == HIGH)
+ *(pinctl.port_buf) |= pinctl.pin;
+ else
+ *(pinctl.port_buf) &= ~pinctl.pin;
+
+ *(pinctl.cfg_buf) |= pinctl.pin;
+ }
+}
+
+static void gpio_buf_apply(
+ volatile uint8_t *gpio_base,
+ uint32_t *port, uint32_t *cfg,
+ uint32_t *mask)
+{
+#if LED_DRIVE_STRENTH != 0
+ uint32_t *drv = (uint32_t *)(gpio_base + GPIO_PD_DRV);
+ *drv = (*drv & ~*mask) | (*cfg & *mask);
+#endif
+ uint32_t *dir = (uint32_t *)(gpio_base + GPIO_DIR);
+ *dir = (*dir & ~*mask) | (*cfg & *mask);
+
+ uint32_t *out = (uint32_t *)(gpio_base + GPIO_OUT);
+ *out = (*out & ~*mask) | (*port & *mask);
+}
+
+static uint32_t PA_buf;
+static uint32_t PB_buf;
+static uint32_t PAcfg_buf;
+static uint32_t PBcfg_buf;
+static uint32_t PA_mask;
+static uint32_t PB_mask;
+
+#define GPIO_APPLY_ALL() \
+ gpio_buf_apply(BA_PA, &PA_buf, &PAcfg_buf, &PA_mask); \
+ gpio_buf_apply(BA_PB, &PB_buf, &PBcfg_buf, &PB_mask)
+
+#define PINCTRL(x, pin) { \
+ &P##x##_buf, \
+ &P##x##cfg_buf, \
+ GPIO_Pin_##pin \
+}
+
+static const pinctrl_t led_pins[LED_PINCOUNT] = {
+ PINCTRL(A, 15), // A
+ PINCTRL(B, 18), // B
+ PINCTRL(B, 0), // C
+ PINCTRL(B, 7), // D
+ PINCTRL(A, 12), // E
+ PINCTRL(A, 10), // F
+ PINCTRL(A, 11), // G
+ PINCTRL(B, 9), // H
+ PINCTRL(B, 8), // I
+ PINCTRL(B, 15), // J
+ PINCTRL(B, 14), // K
+ PINCTRL(B, 13), // L
+ PINCTRL(B, 12), // M
+ PINCTRL(B, 5), // N
+ PINCTRL(A, 4), // O
+ PINCTRL(B, 3), // P
+ PINCTRL(B, 4), // Q
+ PINCTRL(B, 2), // R
+ PINCTRL(B, 1), // S
+ PINCTRL(B, 23), // T
+ PINCTRL(B, 21), // U
+ PINCTRL(B, 20), // V
+ PINCTRL(B, 19), // W
+};
+
+void led_init()
+{
+ for (int i=0; i<LED_PINCOUNT; i++) {
+ if (led_pins[i].port_buf == &PA_buf)
+ PA_mask |= led_pins[i].pin;
+ else
+ PB_mask |= led_pins[i].pin;
+ }
+}
+
+void leds_releaseall() {
+ for (int i=0; i<LED_PINCOUNT; i++)
+ gpio_buf_set(led_pins[i], FLOATING);
+ GPIO_APPLY_ALL();
+}
+
+static void led_write2dcol_raw(int dcol, uint32_t val)
+{
+ // TODO: assert params
+ gpio_buf_set(led_pins[dcol], HIGH);
+ for (int i=0; i<LED_PINCOUNT; i++) {
+ if (i == dcol) continue;
+ gpio_buf_set(led_pins[i], (val & 0x01) ? LOW : FLOATING); // danger: floating=0 (led off) or low=1 (led on)
+ val >>= 1;
+ }
+ GPIO_APPLY_ALL();
+}
+
+static uint32_t combine_cols(uint16_t col1_val, uint16_t col2_val)
+{
+ uint32_t dval = 0;
+ dval |= ((col1_val & 0x01) << (LED_ROWS*2));
+ dval |= ((col2_val & 0x01) << (LED_ROWS*2+1));
+ for (int i=0; i<LED_ROWS; i++) {
+ col1_val >>= 1;
+ col2_val >>= 1;
+
+ dval >>= 2;
+ dval |= ((col1_val & 0x01) << (LED_ROWS*2));
+ dval |= ((col2_val & 0x01) << (LED_ROWS*2+1));
+ }
+ return dval;
+}
+
+void led_write2dcol(int dcol, uint16_t col1_val, uint16_t col2_val)
+{
+ led_write2dcol_raw(dcol, combine_cols(col1_val, col2_val));
+}
+
+void led_write2row_raw(int row, int which_half, uint32_t val)
+{
+ row = row*2 + (which_half != 0);
+
+ gpio_buf_set(led_pins[row], LOW);
+ for (int i=0; i<LED_PINCOUNT; i++) {
+ if (i == row) continue;
+ gpio_buf_set(led_pins[i], (val & 0x01) ? HIGH : FLOATING);
+ val >>= 1;
+ }
+ GPIO_APPLY_ALL();
+}
diff --git a/src/leddrv.h b/src/leddrv.h
new file mode 100644
index 0000000..b9be6ba
--- /dev/null
+++ b/src/leddrv.h
@@ -0,0 +1,14 @@
+#ifndef __LEDDRV_H__
+#define __LEDDRV_H__
+
+#include "CH58x_common.h"
+
+#define LED_COLS 44
+#define LED_ROWS 11
+
+void led_init();
+void leds_releaseall();
+void led_write2dcol(int dcol, uint16_t col1_val, uint16_t col2_val);
+void led_write2row_raw(int row, int which_half, uint32_t val);
+
+#endif /* __LEDDRV_H__ */
diff --git a/src/main.c b/src/main.c
index f504d29..4982ba0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,30 +1,88 @@
#include "CH58x_common.h"
#include "CH58x_sys.h"
+#include "leddrv.h"
-void led_init(void)
-{
- GPIOA_SetBits(GPIO_Pin_10);
- GPIOA_ResetBits(GPIO_Pin_12);
- GPIOA_ModeCfg(GPIO_Pin_10, GPIO_ModeOut_PP_5mA);
- GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeOut_PP_5mA);
-}
+#define FB_WIDTH LED_COLS*4
+#define SCROLL_IRATIO 3
+
+uint16_t fb[2][FB_WIDTH];
+
+uint8_t test_font[][11] = {
+ 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0xF0, 0x00, // F
+ 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, // O
+ 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, // S
+ 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, // S
+ 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, // A
+ 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0xC6, 0x7C, 0x00, // S
+ 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, // I
+ 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, // A
+};
-void led_toggle(void)
+void draw2fb(uint16_t *fb, int c, int col)
{
- GPIOA_InverseBits(GPIO_Pin_10);
- GPIOA_InverseBits(GPIO_Pin_12);
+ uint16_t tmpfb[8] = {0};
+ for (int i=0; i<8; i++) {
+ for (int j=0; j<11; j++) {
+ tmpfb[i] |= ((test_font[c][j] >> (8-i)) & 0x01) << j;
+ }
+ }
+ for (int i=0; i<8; i++) {
+ fb[col+i] = tmpfb[i];
+ }
}
+volatile int fb_sel = 0;
+
int main()
{
SetSysClock(CLK_SOURCE_PLL_60MHz);
led_init();
+ draw2fb(fb[0], 0, 8*5);
+ draw2fb(fb[0], 1, 8*6);
+ draw2fb(fb[0], 2, 8*7);
+ draw2fb(fb[0], 3, 8*8);
+ draw2fb(fb[0], 4, 8*9);
+ draw2fb(fb[0], 5, 8*10);
+ draw2fb(fb[0], 6, 8*11);
+ draw2fb(fb[0], 7, 8*12);
+
+ draw2fb(fb[1], 4, 8*5);
+ draw2fb(fb[1], 5, 8*6);
+ draw2fb(fb[1], 6, 8*7);
+ draw2fb(fb[1], 7, 8*8);
+ draw2fb(fb[1], 0, 8*9);
+ draw2fb(fb[1], 1, 8*10);
+ draw2fb(fb[1], 2, 8*11);
+ draw2fb(fb[1], 3, 8*12);
- while(1)
- {
- mDelaymS(100);
- led_toggle();
+ TMR0_TimerInit(1500);
+ TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END);
+ PFIC_EnableIRQ(TMR0_IRQn);
+
+ while (1) {
}
}
+__attribute__((interrupt))
+void TMR0_IRQHandler(void)
+{
+ static int i, scroll;
+
+ if (TMR0_GetITFlag(TMR0_3_IT_CYC_END)) {
+
+ i += 2;
+ if (i >= LED_COLS) {
+ i = 0;
+ scroll++;
+ if (scroll >= (FB_WIDTH-LED_COLS)*SCROLL_IRATIO) {
+ scroll = 0;
+ fb_sel = fb_sel == 0;
+ }
+ }
+ // This is a mess
+ led_write2dcol(i/2, fb[fb_sel][i+scroll/SCROLL_IRATIO], fb[fb_sel][i+scroll/SCROLL_IRATIO+1]);
+
+ TMR0_ClearITFlag(TMR0_3_IT_CYC_END);
+ }
+}