cancel
Showing results for 
Search instead for 
Did you mean: 

First time programming a stm 32 - key matrix

JLoes.1
Associate

Hello all!

I'm in the process of designing my first full custom sim racing steering wheel. I have designed and ordered a pcb with a stm32f103cbt6 mcu. The pcb works good (so far) and i have it connected to my pc via a swd clone st link debugger.

I am using stm32cubeid to program the pcb and so far everything works. I have configured the basic such as the clock and usb as virtual com port. Now i need to program the rest of the pcb.

The pcb got 14 push buttons and 4 rotary encoders with push button function. So 16 push functions in total. I used the multiplex technology with 4 rows and 4 cols. In stm32cubeide i have set the pins where the rows and cols are connected to gpio_input and generated the code. But my programming skills are not the best, it is not 0, but c scripting i have not done much before.

Can somebody help on the right pad or link me some good tutorials? I get a lot push button to light up led's, but that is not quite what i want. The purpose is to get a push button input mapped into racing games.

2 REPLIES 2
gbm
Lead II

AFAIK, the F103 does not support built-in pull-ups on lines configured as OD outputs. If this is true, then matrix scan is slightly harder than in later STM32 series. Use SysTick interrupt, implement state machine within it, invoked every 10 ms.

Initially set all row port lines as OD outputs driven low and column lines as inputs pulled up.

The states are:

Press detect: in this state all row port lines are set as OD outputs driven low and column lines as inputs pulled up. If any column input is detected as 0, set row lines as inputs pulled up and the detected column line as OD output driven low; record the column number, switch to row detect state.

Row detect: check if any of row inputs is low. If not - go to press detect state. If yes - determine the active row number and computer the key code based on detected column and row number. Set row and column pins as in press detect state, go to release detect state.

Release detect: check if all columns are inactive (high) if yes, go to press detect; otherwise stay in release detect.

JLoes.1
Associate

I did get a bit further with my pcb and i have written a code. I flashed the pcb but it is not quite working as expected. When i connect the pcb and push a button my mouse will move down and my pc won't register a input (tested this in iracing). The code i now have is as followed:

#include "main.h"
#include "usb_device.h"
#include "stm32f1xx_hal.h"
#include "usb_device.h"
#include "usbd_core.h"
 
extern USBD_HandleTypeDef hUsbDeviceFS;
 
extern uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev,
                            uint8_t *report,
                            uint16_t len);
#define ROWS 4
#define COLS 4
uint8_t key_states[4][4] = {0};
void send_keyboard_key(uint8_t keycode) {
    uint8_t keyboard_report[8] = {0};
    keyboard_report[0] = 0x02; // Modifier byte (all zeroes for no modifiers)
    keyboard_report[2] = keycode; // Keycode byte
    USBD_HID_SendReport(&hUsbDeviceFS, keyboard_report, 8);
    keyboard_report[0] = 0; // Release the key by sending a report with all zeroes
    keyboard_report[2] = 0;
    USBD_HID_SendReport(&hUsbDeviceFS, keyboard_report, 8);
}
 
 while (1)
  {
    /* USER CODE END WHILE */
	  // Loop through each row and scan the key matrix
	  for (int row = 0; row < 4; row++) {
	      // Set the current row to a low state
	      if (row == 0) {
	          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
	      } else {
	          HAL_GPIO_WritePin(GPIOB, (1 << (row+3)), GPIO_PIN_RESET);
	      }
 
	      // Wait a short period of time for the signal to stabilize
	      HAL_Delay(1);
 
	      // Read the state of each column pin to detect which buttons are being pressed
	      for (int col = 0; col < 4; col++) {
	          if (!HAL_GPIO_ReadPin(GPIOB, (1 << col))) {
	              key_states[row][col] = 1;
	              switch(row * 4 + col) {
	                  case 0:
	                      send_keyboard_key(0x01);
	                      break;
	                  case 1:
	                      send_keyboard_key(0x02);
	                      break;
	                  case 2:
	                      send_keyboard_key(0x03);
	                      break;
	                  case 3:
	                      send_keyboard_key(0x04);
	                      break;
	                  case 4:
	                      send_keyboard_key(0x05);
	                      break;
	                  case 5:
	                      send_keyboard_key(0x06);
	                      break;
	                  case 6:
	                      send_keyboard_key(0x07);
	                      break;
	                  case 7:
	                      send_keyboard_key(0x08);
	                      break;
	                  case 8:
	                      send_keyboard_key(0x09);
	                      break;
	                  case 9:
	                      send_keyboard_key(0x0A);
	                      break;
	                  case 10:
	                      send_keyboard_key(0x0B);
	                      break;
	                  case 11:
	                      send_keyboard_key(0x0C);
	                      break;
	                  case 12:
	                      send_keyboard_key(0x0D);
	                      break;
	                  case 13:
	                      send_keyboard_key(0x0E);
	                      break;
	                  case 14:
	                      send_keyboard_key(0x0F);
	                      break;
	                  case 15:
	                      send_keyboard_key(0x10);
	                      break;
	              }
	          } else {
	              key_states[row][col] = 0;
	          }
	      }
	  }
 
	  int row = 0;
	      // Set the current row back to a high state
	      if (row == 0) {
	          HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
	      } else {
	          HAL_GPIO_WritePin(GPIOB, (1 << (row+3)), GPIO_PIN_SET);
	      }
	  }