diff --git a/f103-ledmatrix.pro b/f103-ledmatrix.pro index 00d38a8..1e6fc24 100644 --- a/f103-ledmatrix.pro +++ b/f103-ledmatrix.pro @@ -82,7 +82,8 @@ HEADERS += \ project/utils/matcher.h \ project/utils/meanbuf.h \ project/display.h \ - project/matrixdsp.h + project/max2719.h \ + project/dotmatrix.h SOURCES += \ lib/cmsis/core_cm3.c \ @@ -140,7 +141,8 @@ SOURCES += \ project/utils/matcher.c \ project/utils/meanbuf.c \ project/display.c \ - project/matrixdsp.c + project/max2719.c \ + project/dotmatrix.c DISTFILES += \ style.astylerc \ diff --git a/project/dotmatrix.c b/project/dotmatrix.c new file mode 100644 index 0000000..0c0d7e7 --- /dev/null +++ b/project/dotmatrix.c @@ -0,0 +1,48 @@ +#include "max2719.h" +#include "dotmatrix.h" +#include "malloc_safe.h" + +DotMatrix_Cfg* dmtx_init(DotMatrix_Init *init) +{ + DotMatrix_Cfg *dmtx = calloc_s(1, sizeof(DotMatrix_Cfg)); + + dmtx->drv.SPIx = init->SPIx; + dmtx->drv.CS_GPIOx = init->CS_GPIOx; + dmtx->drv.CS_PINx = init->CS_PINx; + dmtx->drv.chain_len = init->cols * init->rows; + dmtx->cols = init->cols; + dmtx->rows = init->rows; + + dmtx->screen = calloc_s(init->cols * init->rows * 8, 1); // 8 bytes per driver + + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_DECODE_MODE, 0x00); // no decode + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_SCAN_LIMIT, 0x07); // scan all 8 + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_SHUTDOWN, 0x01); // not shutdown + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_DISPLAY_TEST, 0x00); // not test + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_INTENSITY, 0x07); // half intensity + + // clear + for (uint8_t i = 0; i < 8; i++) { + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_DIGIT0+i, 0); + } + + return dmtx; +} + +void dmtx_show(DotMatrix_Cfg* dmtx) +{ + for (uint8_t i = 0; i < 8; i++) { + // show each digit's array in turn + max2719_cmd_all_data(&dmtx->drv, MAX2719_CMD_DIGIT0+i, dmtx->screen + (i * dmtx->drv.chain_len)); + } +} + +void dmtx_intensity(DotMatrix_Cfg* dmtx, uint8_t intensity) +{ + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_INTENSITY, intensity & 0x0F); +} + +void dmtx_blank(DotMatrix_Cfg* dmtx, bool blank) +{ + max2719_cmd_all(&dmtx->drv, MAX2719_CMD_SHUTDOWN, blank & 0x01); +} diff --git a/project/dotmatrix.h b/project/dotmatrix.h new file mode 100644 index 0000000..bba0e66 --- /dev/null +++ b/project/dotmatrix.h @@ -0,0 +1,37 @@ +#ifndef MATRIXDSP_H +#define MATRIXDSP_H + +#include "main.h" +#include "max2719.h" + +typedef struct { + MAX2719_Cfg drv; + uint8_t *screen; /*!< Screen array, organized as series of [all #1 digits], [all #2 digits] ... */ + uint32_t cols; /*!< Number of drivers horizontally */ + uint32_t rows; /*!< Number of drivers vertically */ +} DotMatrix_Cfg; + +typedef struct { + SPI_TypeDef *SPIx; /*!< SPI iface used by this instance */ + GPIO_TypeDef *CS_GPIOx; /*!< Chip select GPIO port */ + uint16_t CS_PINx; /*!< Chip select pin mask */ + uint32_t cols; /*!< Number of drivers horizontally */ + uint32_t rows; /*!< Number of drivers vertically */ +} DotMatrix_Init; + + +DotMatrix_Cfg* dmtx_init(DotMatrix_Init *init); + +/** + * @brief Display the whole screen array + * @param dmtx : driver struct + */ +void dmtx_show(DotMatrix_Cfg* dmtx); + +/** Set intensity 0-16 */ +void dmtx_intensity(DotMatrix_Cfg* dmtx, uint8_t intensity); + +/** Display on/off */ +void dmtx_blank(DotMatrix_Cfg* dmtx, bool blank); + +#endif // MATRIXDSP_H diff --git a/project/main.c b/project/main.c index a83d335..534b753 100644 --- a/project/main.c +++ b/project/main.c @@ -13,104 +13,71 @@ #include #include -#include "matrixdsp.h" +//#include "matrixdsp.h" +#include "max2719.h" +#include "dotmatrix.h" -static void poll_subsystems(void) -{ - // poll serial buffers (runs callback) - com_poll(debug_iface); - com_poll(data_iface); - - // run queued tasks - tq_poll(); - - // handle queued events - Event evt; - - until_timeout(2) { // take 2 ms max - if (eq_take(&evt)) { - run_event_handler(&evt); - } else { - break; - } - } -} +static void poll_subsystems(void); +static DotMatrix_Cfg *dmtx; int main(void) { hw_init(); -// display_init(); banner("*** LED MATRIX DEMO ***"); banner_info("(c) Ondrej Hruska, 2016"); banner_info("Katedra mereni K338, CVUT FEL"); - ms_time_t last; + DotMatrix_Init dmtx_cfg; + dmtx_cfg.CS_GPIOx = GPIOA; + dmtx_cfg.CS_PINx = GPIO_Pin_4; + dmtx_cfg.SPIx = SPI1; + dmtx_cfg.cols = 4; + dmtx_cfg.rows = 1; - mdsp_send_command_all(CMD_DECODE_MODE, 0x00); - mdsp_send_command_all(CMD_SCAN_LIMIT, 0x07); - mdsp_send_command_all(CMD_SHUTDOWN, 0x01); - mdsp_send_command_all(CMD_DISPLAY_TEST, 0x00); - mdsp_send_command_all(CMD_INTENSITY, 0x0F); - - mdsp_clear(); - - // --- - - const uint16_t inva0[] = { - 0b00100000100, - 0b00010001000, - 0b00111111100, - 0b01101110110, - 0b11111111111, - 0b10111111101, - 0b10100000101, - 0b00011011000, - }; - - const uint16_t inva1[] = { - 0b00100000100, - 0b10010001001, - 0b10111111101, - 0b11101110111, - 0b11111111111, - 0b01111111110, - 0b00100000100, - 0b01000000010, - }; + dmtx = dmtx_init(&dmtx_cfg); + dmtx->screen[0] = 0xF0; + dmtx->screen[4] = 0x0F; + + dmtx_show(dmtx); + + ms_time_t last; while (1) { if (ms_loop_elapsed(&last, 500)) { GPIOC->ODR ^= 1 << 13; } - poll_subsystems(); - for(int i = 0; i < 8; i++) { - mdsp_send_command_all(CMD_DIGIT0+i, i); - } - delay_ms(500); + dmtx_blank(dmtx, false); + delay_ms(250); + dmtx_blank(dmtx, true); + delay_ms(250); + } +} - for(int i = 7; i >= 0; i--) { - mdsp_send_command_all(CMD_DIGIT0+i, 0x00); - } - delay_ms(500); - /*for (int i = 0; i < 8; i++) { - uint32_t x = __RBIT(inva0[7-i]); - mdsp_set(i, x >> 21); - mdsp_set(8+i, (x >> 29) & 0b111); - } - delay_ms(500); - for (int i = 0; i < 8; i++) { - uint32_t x = __RBIT(inva1[7-i]); - mdsp_set(i, x >> 21); - mdsp_set(8+i, (x >> 29) & 0b111); +static void poll_subsystems(void) +{ + // poll serial buffers (runs callback) + com_poll(debug_iface); + com_poll(data_iface); + + // run queued tasks + tq_poll(); + + // handle queued events + Event evt; + + until_timeout(2) { // take 2 ms max + if (eq_take(&evt)) { + run_event_handler(&evt); + } else { + break; } - delay_ms(500);*/ } } diff --git a/project/malloc_safe.c b/project/malloc_safe.c index 2f3919c..a8720b3 100644 --- a/project/malloc_safe.c +++ b/project/malloc_safe.c @@ -29,7 +29,7 @@ void *malloc_safe_do(size_t size, const char* file, uint32_t line) void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line) { - void *mem = calloc(size, nmemb); + void *mem = calloc(nmemb, size); if (mem == NULL) { // malloc failed error("Malloc failed in file %s on line %"PRIu32, file, line); diff --git a/project/matrixdsp.c b/project/matrixdsp.c deleted file mode 100644 index 792f8d4..0000000 --- a/project/matrixdsp.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include - -#include "com/debug.h" - -#include "utils/timebase.h" - -static void send_byte(uint8_t b) -{ - MDSP_SPIx->DR = b; - while (!(MDSP_SPIx->SR & SPI_SR_TXE)); -} - -static void set_nss(bool nss) -{ - if (nss) { - MDSP_NSS_GPIO->BSRR = MDSP_NSS_PIN; - } else { - MDSP_NSS_GPIO->BRR = MDSP_NSS_PIN; - } -} - -static void send_word(MDSP_Command cmd, uint8_t data) -{ - send_byte(cmd); - send_byte(data); -} - -/** - * @brief Send a command to n-th chained driver - * @param idx Driver index (0, 1, 2 ...) - * @param cmd command to send - * @param data command argument - */ -void mdsp_send_command(uint8_t idx, MDSP_Command cmd, uint8_t data) -{ - dbg("Set %d: cmd 0x%02x, data 0x%02x", idx, cmd, data); - - set_nss(false); - while (MDSP_SPIx->SR & SPI_SR_BSY); - - for (uint8_t i = 0; i < MDSP_CHAIN_COUNT - idx - 1; i++) { - send_word(CMD_NOOP, 0); - } - - send_word(cmd, data); - - for (uint8_t i = 0; i < idx; i++) { - send_word(CMD_NOOP, 0); - } - - while (MDSP_SPIx->SR & SPI_SR_BSY); - set_nss(false); - set_nss(true); -} - - -void mdsp_send_command_all(MDSP_Command cmd, uint8_t data) -{ - //dbg("Set cmd 0x%02x, data 0x%02x ALL", cmd, data); - - set_nss(false); - while (MDSP_SPIx->SR & SPI_SR_BSY); - - for (uint8_t i = 0; i < MDSP_CHAIN_COUNT; i++) { - send_word(cmd, data); - } - - while (MDSP_SPIx->SR & SPI_SR_BSY); - set_nss(false); - set_nss(true); -} - -void mdsp_set(uint8_t column, uint8_t bits) -{ - if (column >= MDSP_COLUMN_COUNT) return; - - mdsp_send_command(column >> 3, CMD_DIGIT0 + (column & 0x7), bits); -} - -void mdsp_clear(void) -{ - for (uint8_t i = 0; i < 8; i++) { - mdsp_send_command_all(CMD_DIGIT0+i, 0); - } -} diff --git a/project/matrixdsp.h b/project/matrixdsp.h deleted file mode 100644 index f9cd124..0000000 --- a/project/matrixdsp.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MATRIXDSP_H -#define MATRIXDSP_H - -#include - -#define MDSP_SPIx SPI1 -#define MDSP_NSS_GPIO GPIOA -#define MDSP_NSS_PIN GPIO_Pin_4; - -#define MDSP_CHAIN_COUNT 4 -#define MDSP_COLUMN_COUNT (MDSP_CHAIN_COUNT*8) - -typedef enum { - CMD_NOOP = 0x00, - - CMD_DIGIT0 = 0x01, - CMD_DIGIT1 = 0x02, - CMD_DIGIT2 = 0x03, - CMD_DIGIT3 = 0x04, - CMD_DIGIT4 = 0x05, - CMD_DIGIT5 = 0x06, - CMD_DIGIT6 = 0x07, - CMD_DIGIT7 = 0x08, - - CMD_DECODE_MODE = 0x09, - CMD_INTENSITY = 0x0A, - CMD_SCAN_LIMIT = 0x0B, - CMD_SHUTDOWN = 0x0C, - CMD_DISPLAY_TEST = 0x0F, -} MDSP_Command; - -void mdsp_set(uint8_t column, uint8_t bits); - -void mdsp_clear(void); - -/** - * @brief Send a command to n-th chained driver - * @param idx Driver index (0, 1, 2 ...) - * @param cmd command to send - * @param data command argument - */ -void mdsp_send_command(uint8_t idx, MDSP_Command cmd, uint8_t data); - - -void mdsp_send_command_all(MDSP_Command cmd, uint8_t data); - -#endif // MATRIXDSP_H diff --git a/project/max2719.c b/project/max2719.c new file mode 100644 index 0000000..b8594dc --- /dev/null +++ b/project/max2719.c @@ -0,0 +1,73 @@ +#include "max2719.h" + +static inline +void send_byte(MAX2719_Cfg *inst, uint8_t b) +{ + inst->SPIx->DR = b; + while (!(inst->SPIx->SR & SPI_SR_TXE)); +} + + +static inline +void set_nss(MAX2719_Cfg *inst, bool nss) +{ + if (nss) { + inst->CS_GPIOx->BSRR = inst->CS_PINx; + } else { + inst->CS_GPIOx->BRR = inst->CS_PINx; + } +} + + +static void send_word(MAX2719_Cfg *inst, MAX2719_Command cmd, uint8_t data) +{ + send_byte(inst, cmd); + send_byte(inst, data); +} + + +void max2719_cmd(MAX2719_Cfg *inst, uint32_t nth, MAX2719_Command cmd, uint8_t data) +{ + set_nss(inst, 0); + while (inst->SPIx->SR & SPI_SR_BSY); + + for (uint32_t i = 0; i < inst->chain_len; i++) { + if (i == inst->chain_len - nth - 1) { + send_word(inst, cmd, data); + } else { + send_word(inst, MAX2719_CMD_NOOP, 0); + } + } + + while (inst->SPIx->SR & SPI_SR_BSY); + set_nss(inst, 1); +} + + + +void max2719_cmd_all(MAX2719_Cfg *inst, MAX2719_Command cmd, uint8_t data) +{ + set_nss(inst, 0); + while (inst->SPIx->SR & SPI_SR_BSY); + + for (uint32_t i = 0; i < inst->chain_len; i++) { + send_word(inst, cmd, data); + } + + while (inst->SPIx->SR & SPI_SR_BSY); + set_nss(inst, 1); +} + + +void max2719_cmd_all_data(MAX2719_Cfg *inst, MAX2719_Command cmd, uint8_t *data) +{ + set_nss(inst, 0); + while (inst->SPIx->SR & SPI_SR_BSY); + + for (uint32_t i = 0; i < inst->chain_len; i++) { + send_word(inst, cmd, data[inst->chain_len - i - 1]); + } + + while (inst->SPIx->SR & SPI_SR_BSY); + set_nss(inst, 1); +} diff --git a/project/max2719.h b/project/max2719.h new file mode 100644 index 0000000..1864c1d --- /dev/null +++ b/project/max2719.h @@ -0,0 +1,61 @@ +#ifndef MAX2719_H +#define MAX2719_H + +#include + +/** Generic utilities for controlling the MAX2719 display driver */ + +typedef struct { + SPI_TypeDef *SPIx; /*!< SPI iface used by this instance */ + GPIO_TypeDef *CS_GPIOx; /*!< Chip select GPIO port */ + uint16_t CS_PINx; /*!< Chip select pin mask */ + uint32_t chain_len; /*!< Number of daisy-chained drivers (for "all" or "n-th" commands */ +} MAX2719_Cfg; + + +typedef enum { + MAX2719_CMD_NOOP = 0x00, + + MAX2719_CMD_DIGIT0 = 0x01, + MAX2719_CMD_DIGIT1 = 0x02, + MAX2719_CMD_DIGIT2 = 0x03, + MAX2719_CMD_DIGIT3 = 0x04, + MAX2719_CMD_DIGIT4 = 0x05, + MAX2719_CMD_DIGIT5 = 0x06, + MAX2719_CMD_DIGIT6 = 0x07, + MAX2719_CMD_DIGIT7 = 0x08, + + MAX2719_CMD_DECODE_MODE = 0x09, + MAX2719_CMD_INTENSITY = 0x0A, + MAX2719_CMD_SCAN_LIMIT = 0x0B, + MAX2719_CMD_SHUTDOWN = 0x0C, + MAX2719_CMD_DISPLAY_TEST = 0x0F, +} MAX2719_Command; + + +/** + * @brief Send a command to a single driver + * @param inst : config struct + * @param nth : driver index + * @param cmd : command + * @param data : data byte + */ +void max2719_cmd(MAX2719_Cfg *inst, uint32_t nth, MAX2719_Command cmd, uint8_t data); + +/** + * @brief Send command to all drivers, with the same data + * @param inst : config struct + * @param cmd : command + * @param data : data byte + */ +void max2719_cmd_all(MAX2719_Cfg *inst, MAX2719_Command cmd, uint8_t data); + +/** + * @brief Send command to all drivers, with varying data + * @param inst : config struct + * @param cmd : command + * @param data : array of data bytes (must be long to cover all drivers) + */ +void max2719_cmd_all_data(MAX2719_Cfg *inst, MAX2719_Command cmd, uint8_t *data); + +#endif // MAX2719_H