/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Arrive LED sign firmware ****************************************************************************** */ /* USER CODE END Header */ #include "main.h" /* USER CODE BEGIN Includes */ #include #include /* USER CODE END Includes */ /* USER CODE BEGIN PD */ #define ROWS 7 #define COLS 96 #define NUM_CHIPS 12 #define ROW_DWELL 500 #define UART_BUF 128 #define WIDE_COLS 512 /* Commands */ #define CMD_CLEAR 0x01 #define CMD_VALUES 0x02 #define CMD_HW_DEPT 0x03 #define CMD_SCROLL 0x04 /* USER CODE END PD */ /* USER CODE BEGIN PM */ /* USER CODE END PM */ SPI_HandleTypeDef hspi1; UART_HandleTypeDef huart2; /* USER CODE BEGIN PV */ typedef struct { GPIO_TypeDef *port; uint16_t pin; } RowPin; static const RowPin ROW_PINS[ROWS] = { {ROW_0_GPIO_Port, ROW_0_Pin}, {ROW_1_GPIO_Port, ROW_1_Pin}, {ROW_2_GPIO_Port, ROW_2_Pin}, {ROW_3_GPIO_Port, ROW_3_Pin}, {ROW_4_GPIO_Port, ROW_4_Pin}, {ROW_5_GPIO_Port, ROW_5_Pin}, {ROW_6_GPIO_Port, ROW_6_Pin}, }; static uint8_t fb[ROWS][NUM_CHIPS]; static uint8_t wide[ROWS][WIDE_COLS]; static uint16_t wide_cols = 0; static int32_t scroll_x = 0; /* UART protocol state */ static uint8_t uart_rx_byte; static char uart_buf[UART_BUF]; static uint8_t uart_idx = 0; static uint8_t uart_cs_acc = 0; static uint8_t uart_cs1 = 0; static uint8_t uart_cs2 = 0; static uint8_t uart_len = 0; static uint8_t uart_cmd = 0; /* Command queue — set by ISR, read by main loop */ static volatile uint8_t pending_cmd = 0; static volatile uint8_t pending_cmd_rdy = 0; static char pending_msg[UART_BUF]; /* Current mode */ static uint8_t current_cmd = 0; static char message[UART_BUF] = ""; /* USER CODE END PV */ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_SPI1_Init(void); static void MX_USART2_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* ── 5x7 font ASCII 32-90 ── */ static const uint8_t FONT[][5] = { {0x00,0x00,0x00,0x00,0x00}, /* ' ' */ {0x00,0x00,0x5F,0x00,0x00}, /* ! */ {0x00,0x07,0x00,0x07,0x00}, /* " */ {0x14,0x7F,0x14,0x7F,0x14}, /* # */ {0x24,0x2A,0x7F,0x2A,0x12}, /* $ */ {0x23,0x13,0x08,0x64,0x62}, /* % */ {0x36,0x49,0x55,0x22,0x50}, /* & */ {0x00,0x05,0x03,0x00,0x00}, /* ' */ {0x00,0x1C,0x22,0x41,0x00}, /* ( */ {0x00,0x41,0x22,0x1C,0x00}, /* ) */ {0x08,0x2A,0x1C,0x2A,0x08}, /* * */ {0x08,0x08,0x3E,0x08,0x08}, /* + */ {0x00,0x50,0x30,0x00,0x00}, /* , */ {0x08,0x08,0x08,0x08,0x08}, /* - */ {0x00,0x60,0x60,0x00,0x00}, /* . */ {0x20,0x10,0x08,0x04,0x02}, /* / */ {0x3E,0x51,0x49,0x45,0x3E}, /* 0 */ {0x00,0x42,0x7F,0x40,0x00}, /* 1 */ {0x42,0x61,0x51,0x49,0x46}, /* 2 */ {0x21,0x41,0x45,0x4B,0x31}, /* 3 */ {0x18,0x14,0x12,0x7F,0x10}, /* 4 */ {0x27,0x45,0x45,0x45,0x39}, /* 5 */ {0x3C,0x4A,0x49,0x49,0x30}, /* 6 */ {0x01,0x71,0x09,0x05,0x03}, /* 7 */ {0x36,0x49,0x49,0x49,0x36}, /* 8 */ {0x06,0x49,0x49,0x29,0x1E}, /* 9 */ {0x00,0x36,0x36,0x00,0x00}, /* : */ {0x00,0x56,0x36,0x00,0x00}, /* ; */ {0x00,0x08,0x14,0x22,0x41}, /* < */ {0x14,0x14,0x14,0x14,0x14}, /* = */ {0x41,0x22,0x14,0x08,0x00}, /* > */ {0x02,0x01,0x51,0x09,0x06}, /* ? */ {0x32,0x49,0x79,0x41,0x3E}, /* @ */ {0x7E,0x09,0x09,0x09,0x7E}, /* A */ {0x7F,0x49,0x49,0x49,0x36}, /* B */ {0x3E,0x41,0x41,0x41,0x22}, /* C */ {0x7F,0x41,0x41,0x41,0x3E}, /* D */ {0x7F,0x49,0x49,0x49,0x41}, /* E */ {0x7F,0x09,0x09,0x09,0x01}, /* F */ {0x3E,0x41,0x49,0x49,0x7A}, /* G */ {0x7F,0x08,0x08,0x08,0x7F}, /* H */ {0x41,0x7F,0x41,0x00,0x00}, /* I */ {0x20,0x40,0x41,0x3F,0x01}, /* J */ {0x7F,0x08,0x14,0x22,0x41}, /* K */ {0x7F,0x40,0x40,0x40,0x40}, /* L */ {0x7F,0x02,0x04,0x02,0x7F}, /* M */ {0x7F,0x04,0x08,0x10,0x7F}, /* N */ {0x3E,0x41,0x41,0x41,0x3E}, /* O */ {0x7F,0x09,0x09,0x09,0x06}, /* P */ {0x3E,0x41,0x51,0x21,0x5E}, /* Q */ {0x7F,0x09,0x19,0x29,0x46}, /* R */ {0x46,0x49,0x49,0x49,0x31}, /* S */ {0x01,0x01,0x7F,0x01,0x01}, /* T */ {0x3F,0x40,0x40,0x40,0x3F}, /* U */ {0x1F,0x20,0x40,0x20,0x1F}, /* V */ {0x7F,0x20,0x10,0x20,0x7F}, /* W */ {0x63,0x14,0x08,0x14,0x63}, /* X */ {0x03,0x04,0x78,0x04,0x03}, /* Y */ {0x61,0x51,0x49,0x45,0x43}, /* Z */ }; /* ── North star ── */ static const uint8_t STAR[7][11] = { {0,0,0,0,1,0,0,0,0,0,0}, {0,0,0,1,1,1,0,0,0,0,0}, {1,1,0,0,1,0,0,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1,1}, {1,1,0,0,1,0,0,1,1,1,1}, {0,0,0,1,1,1,0,0,0,0,0}, {0,0,0,0,1,0,0,0,0,0,0}, }; /* ── ARRIVE glyph 7x36 ── */ static const uint8_t ARRIVE_GLYPH[7][36] = { {0,1,1,1,0,0, 0,1,1,1,0,0, 0,1,1,1,0,0, 0,1,1,1,0,0, 1,0,0,0,1,0, 1,1,1,1,1,0}, {1,0,0,0,1,0, 1,0,0,0,1,0, 1,0,0,0,1,0, 0,0,1,0,0,0, 1,0,0,0,1,0, 1,0,0,0,0,0}, {1,0,0,0,1,0, 1,0,0,0,1,0, 1,0,0,0,1,0, 0,0,1,0,0,0, 1,0,0,0,1,0, 1,0,0,0,0,0}, {1,1,1,1,1,0, 1,1,1,1,0,0, 1,1,1,1,0,0, 0,0,1,0,0,0, 0,1,0,1,0,0, 1,1,1,1,0,0}, {1,0,0,0,1,0, 1,0,1,0,0,0, 1,0,1,0,0,0, 0,0,1,0,0,0, 0,1,0,1,0,0, 1,0,0,0,0,0}, {1,0,0,0,1,0, 1,0,0,1,0,0, 1,0,0,1,0,0, 0,0,1,0,0,0, 0,0,1,0,0,0, 1,0,0,0,0,0}, {1,0,0,0,1,0, 1,0,0,0,1,0, 1,0,0,0,1,0, 0,1,1,1,0,0, 0,0,1,0,0,0, 1,1,1,1,1,0}, }; /* ════════════════════════════════════════════════ Low level display helpers ════════════════════════════════════════════════ */ static void delay_us(uint32_t us) { uint32_t start = DWT->CYCCNT; uint32_t ticks = (SystemCoreClock / 1000000U) * us; while ((DWT->CYCCNT - start) < ticks); } static void all_rows_off(void) { for (int i = 0; i < ROWS; i++) HAL_GPIO_WritePin(ROW_PINS[i].port, ROW_PINS[i].pin, GPIO_PIN_SET); } static void display_refresh(void) { for (int row = 0; row < ROWS; row++) { all_rows_off(); HAL_SPI_Transmit(&hspi1, fb[row], NUM_CHIPS, HAL_MAX_DELAY); HAL_GPIO_WritePin(ROW_PINS[row].port, ROW_PINS[row].pin, GPIO_PIN_RESET); delay_us(ROW_DWELL); } all_rows_off(); } static void refresh_for(uint32_t ms) { uint32_t t = HAL_GetTick(); while ((HAL_GetTick() - t) < ms) { display_refresh(); } } /* ── Check if a new command arrived — call from long-running loops ── */ static uint8_t check_new_cmd(void) { return pending_cmd_rdy; } /* ════════════════════════════════════════════════ Framebuffer helpers ════════════════════════════════════════════════ */ static void fb_set_pixel(int col, int row, uint8_t on) { if (col < 0 || col >= COLS || row < 0 || row >= ROWS) return; int chip = col / 8; int bit = 7 - (col % 8); if (on) fb[row][chip] |= (uint8_t)(1 << bit); else fb[row][chip] &= ~(uint8_t)(1 << bit); } static void render_logo(int star_col, int text_col, int mask_col) { memset(fb, 0, sizeof(fb)); for (int row = 0; row < 7; row++) { for (int sc = 0; sc < 11; sc++) { int col = star_col + sc; if (STAR[row][sc] && (mask_col < 0 || col >= mask_col)) fb_set_pixel(col, row, 1); } for (int tc = 0; tc < 36; tc++) { int col = text_col + tc; if (ARRIVE_GLYPH[row][tc] && (mask_col < 0 || col >= mask_col)) fb_set_pixel(col, row, 1); } } } static void render_logo_rows(int star_col, int text_col, uint8_t row_mask) { memset(fb, 0, sizeof(fb)); for (int row = 0; row < 7; row++) { if (!(row_mask & (1 << row))) continue; for (int sc = 0; sc < 11; sc++) { int col = star_col + sc; if (STAR[row][sc]) fb_set_pixel(col, row, 1); } for (int tc = 0; tc < 36; tc++) { int col = text_col + tc; if (ARRIVE_GLYPH[row][tc]) fb_set_pixel(col, row, 1); } } } /* ── Draw text string into fb at given x offset, return end col ── */ static int render_text_to_fb(const char *txt, int x_offset) { int col = x_offset; while (*txt) { uint8_t c = (uint8_t)*txt++; if (c >= 'a' && c <= 'z') c -= 32; if (c >= 32 && c <= 90) { const uint8_t *g = FONT[c - 32]; for (int i = 0; i < 5; i++, col++) { for (int row = 0; row < ROWS; row++) { if (g[i] & (1 << row)) fb_set_pixel(col, row, 1); } } } col++; } return col; } /* ── Render text centred on display ── */ static void render_centred_text(const char *txt) { int len = 0; const char *p = txt; while (*p++) len++; int text_width = len * 6 - 1; int x = (COLS - text_width) / 2; memset(fb, 0, sizeof(fb)); render_text_to_fb(txt, x); } /* ── Render word into wide[] for scrolling, returns total width ── */ static uint16_t render_scroll(const char *txt, int x_start) { memset(wide, 0, sizeof(wide)); int col = x_start; while (*txt && col < WIDE_COLS - 6) { uint8_t c = (uint8_t)*txt++; if (c >= 'a' && c <= 'z') c -= 32; if (c >= 32 && c <= 90) { const uint8_t *g = FONT[c - 32]; for (int i = 0; i < 5 && col < WIDE_COLS; i++, col++) { for (int row = 0; row < ROWS; row++) { if (g[i] & (1 << row)) wide[row][col] = 1; } } } col++; } return (uint16_t)(col + COLS); } static void update_fb_from_scroll(void) { for (int row = 0; row < ROWS; row++) { memset(fb[row], 0, NUM_CHIPS); for (int col = 0; col < COLS; col++) { uint16_t src = (uint16_t)(scroll_x + col); if (src < WIDE_COLS && wide[row][src]) fb_set_pixel(col, row, 1); } } } /* ── Update fb from scroll but only write to cols >= clip_left ── */ static void update_fb_from_scroll_clipped(int clip_left) { for (int row = 0; row < ROWS; row++) { for (int col = clip_left; col < COLS; col++) { uint16_t src = (uint16_t)(scroll_x + (col - clip_left)); if (src < WIDE_COLS) fb_set_pixel(col, row, wide[row][src]); } } } /* ── Fade rows out (centre outward to top+bottom) ── */ static void fade_out_rows(int star_col, int text_col, uint8_t is_logo) { uint8_t masks[] = {0x7E, 0x7C, 0x3C, 0x1C, 0x0C, 0x08, 0x00}; uint8_t snap[ROWS][NUM_CHIPS]; memcpy(snap, fb, sizeof(fb)); for (int i = 0; i < 7; i++) { if (is_logo) { render_logo_rows(star_col, text_col, masks[i]); } else { memset(fb, 0, sizeof(fb)); for (int row = 0; row < ROWS; row++) { if (masks[i] & (1 << row)) memcpy(fb[row], snap[row], NUM_CHIPS); } } refresh_for(60); } memset(fb, 0, sizeof(fb)); } /* ════════════════════════════════════════════════ Arrive boot / splash animation ════════════════════════════════════════════════ */ static void arrive_animation(void) { const int text_col = 23; const int star_col = 61; /* Phase 1 — star builds */ memset(fb, 0, sizeof(fb)); for (int row = 0; row < 7; row++) fb_set_pixel(star_col + 4, row, 1); for (int sc = 3; sc <= 5; sc++) fb_set_pixel(star_col + sc, 3, 1); refresh_for(120); memset(fb, 0, sizeof(fb)); for (int row = 0; row < 7; row++) for (int sc = 3; sc <= 7; sc++) if (STAR[row][sc]) fb_set_pixel(star_col + sc, row, 1); refresh_for(120); render_logo(star_col, text_col, star_col); refresh_for(150); /* Phase 2 — glint pulse */ memset(fb, 0, sizeof(fb)); refresh_for(80); render_logo(star_col, text_col, star_col); refresh_for(80); memset(fb, 0, sizeof(fb)); refresh_for(60); render_logo(star_col, text_col, star_col); refresh_for(100); /* Phase 3 — wipe reveal */ for (int mask = star_col; mask >= text_col - 1; mask -= 2) { render_logo(star_col, text_col, mask); refresh_for(18); } render_logo(star_col, text_col, -1); /* Phase 4 — hold */ refresh_for(2000); /* Phase 5 — fade out */ fade_out_rows(star_col, text_col, 1); refresh_for(200); } /* ════════════════════════════════════════════════ CMD_VALUES — Curious / Focused / Together loop ════════════════════════════════════════════════ */ static const char *VALUES_WORDS[] = { "CURIOUS", "FOCUSED", "TOGETHER" }; #define VALUES_COUNT 3 static void run_values(void) { uint8_t idx = 0; while (!check_new_cmd()) { /* Arrive splash with fade out */ arrive_animation(); if (check_new_cmd()) break; /* Display word centred — no fade in, just show it */ render_centred_text(VALUES_WORDS[idx]); refresh_for(2500); if (check_new_cmd()) break; /* Fade out same as arrive splash — rows collapse inward */ fade_out_rows(0, 0, 0); if (check_new_cmd()) break; /* Wait before next cycle */ memset(fb, 0, sizeof(fb)); refresh_for(600); if (check_new_cmd()) break; idx = (idx + 1) % VALUES_COUNT; } } /* ════════════════════════════════════════════════ CMD_HW_DEPT — logo left, scrolling text right ════════════════════════════════════════════════ */ /* Small logo: text_col=2, star_col=40, total=53 cols Leaves cols 54-95 (42 cols) for scroll text */ #define HW_TEXT_COL 2 #define HW_STAR_COL 40 #define HW_SCROLL_START 54 static void run_hw_dept(void) { const char *hw_txt = "HARDWARE DEPT "; /* Start text one scroll-zone width to the right so it scrolls in from edge */ const int scroll_zone = COLS - HW_SCROLL_START; /* ~42 cols */ uint16_t hw_wide_cols = render_scroll(hw_txt, scroll_zone); int32_t hw_scroll_x = 0; uint32_t last_scroll = HAL_GetTick(); const uint32_t scroll_ms = 40; while (!check_new_cmd()) { /* Draw logo into fb */ render_logo(HW_STAR_COL, HW_TEXT_COL, -1); /* Overlay scrolling text on right side */ update_fb_from_scroll_clipped(HW_SCROLL_START); /* Advance scroll */ if ((HAL_GetTick() - last_scroll) >= scroll_ms) { last_scroll = HAL_GetTick(); hw_scroll_x++; if (hw_scroll_x >= hw_wide_cols) hw_scroll_x = 0; scroll_x = hw_scroll_x; } display_refresh(); } } /* ════════════════════════════════════════════════ CMD_SCROLL — scroll arbitrary text ════════════════════════════════════════════════ */ static void run_scroll(void) { wide_cols = render_scroll(message, COLS); scroll_x = 0; update_fb_from_scroll(); uint32_t last_scroll = HAL_GetTick(); const uint32_t scroll_ms = 40; while (!check_new_cmd()) { if ((HAL_GetTick() - last_scroll) >= scroll_ms) { last_scroll = HAL_GetTick(); scroll_x++; if (scroll_x >= wide_cols) scroll_x = 0; update_fb_from_scroll(); } display_refresh(); } } /* ════════════════════════════════════════════════ UART protocol state machine Packet: 'A' 'R' CMD LEN CS1 CS2 [MSG...] CS1 = sum(msg) & 0xFF CS2 = ~CS1 & 0xFF ════════════════════════════════════════════════ */ typedef enum { UART_WAIT_A, UART_WAIT_R, UART_WAIT_CMD, UART_WAIT_LEN, UART_WAIT_CS1, UART_WAIT_CS2, UART_WAIT_DATA, } UartState; static UartState uart_state = UART_WAIT_A; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance != USART2) return; uint8_t b = uart_rx_byte; switch (uart_state) { case UART_WAIT_A: if (b == 'A') uart_state = UART_WAIT_R; break; case UART_WAIT_R: uart_state = (b == 'R') ? UART_WAIT_CMD : UART_WAIT_A; break; case UART_WAIT_CMD: uart_cmd = b; uart_state = UART_WAIT_LEN; break; case UART_WAIT_LEN: uart_len = b; uart_idx = 0; uart_cs_acc = 0; uart_state = UART_WAIT_CS1; break; case UART_WAIT_CS1: uart_cs1 = b; uart_state = UART_WAIT_CS2; break; case UART_WAIT_CS2: uart_cs2 = b; uart_state = (uart_len > 0) ? UART_WAIT_DATA : UART_WAIT_A; if (uart_len == 0) { /* No payload — validate empty checksum (cs1=cs2=0 for empty) */ pending_cmd = uart_cmd; pending_msg[0] = '\0'; pending_cmd_rdy = 1; } break; case UART_WAIT_DATA: uart_buf[uart_idx++] = (char)b; uart_cs_acc += b; if (uart_idx >= uart_len) { uart_buf[uart_idx] = '\0'; uint8_t cs1c = uart_cs_acc & 0xFF; uint8_t cs2c = (~uart_cs_acc) & 0xFF; if (cs1c == uart_cs1 && cs2c == uart_cs2) { memcpy(pending_msg, uart_buf, uart_idx + 1); pending_cmd = uart_cmd; pending_cmd_rdy = 1; } uart_state = UART_WAIT_A; uart_idx = 0; } break; } HAL_UART_Receive_IT(&huart2, &uart_rx_byte, 1); } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ MX_GPIO_Init(); MX_SPI1_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; all_rows_off(); memset(fb, 0, sizeof(fb)); HAL_UART_Receive_IT(&huart2, &uart_rx_byte, 1); arrive_animation(); memset(fb, 0, sizeof(fb)); current_cmd = 0; /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ while (1) { if (pending_cmd_rdy) { pending_cmd_rdy = 0; current_cmd = pending_cmd; memcpy(message, pending_msg, sizeof(pending_msg)); } switch (current_cmd) { case CMD_CLEAR: memset(fb, 0, sizeof(fb)); display_refresh(); current_cmd = 0; break; case CMD_VALUES: run_values(); break; case CMD_HW_DEPT: run_hw_dept(); break; case CMD_SCROLL: run_scroll(); break; default: display_refresh(); break; } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4; RCC_OscInitStruct.PLL.PLLN = 85; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) Error_Handler(); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) Error_Handler(); } static void MX_SPI1_Init(void) { /* USER CODE BEGIN SPI1_Init 0 */ /* USER CODE END SPI1_Init 0 */ /* USER CODE BEGIN SPI1_Init 1 */ /* USER CODE END SPI1_Init 1 */ hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 7; hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE; hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE; if (HAL_SPI_Init(&hspi1) != HAL_OK) Error_Handler(); /* USER CODE BEGIN SPI1_Init 2 */ /* USER CODE END SPI1_Init 2 */ } static void MX_USART2_UART_Init(void) { /* USER CODE BEGIN USART2_Init 0 */ /* USER CODE END USART2_Init 0 */ /* USER CODE BEGIN USART2_Init 1 */ /* USER CODE END USART2_Init 1 */ huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1; huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart2) != HAL_OK) Error_Handler(); if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK) Error_Handler(); if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK) Error_Handler(); if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK) Error_Handler(); /* USER CODE BEGIN USART2_Init 2 */ /* USER CODE END USART2_Init 2 */ } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOA, ROW_1_Pin|ROW_2_Pin|ROW_6_Pin|ROW_5_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, ROW_0_Pin|ROW_3_Pin|ROW_4_Pin|LED_Pin, GPIO_PIN_SET); GPIO_InitStruct.Pin = ROW_1_Pin|ROW_2_Pin|ROW_6_Pin|ROW_5_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = ROW_0_Pin|ROW_3_Pin|ROW_4_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = LED_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ __disable_irq(); while (1) {} /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT void assert_failed(uint8_t *file, uint32_t line) {} #endif