2026-01-28 9:27 PM - edited 2026-01-28 9:45 PM
I want to make a pedometer app that would count steps and display the number of steps on an LCD screen.
I have tested my functions for the screen (ILI9341 SPI), and they work successfully. I tested the LCD code by initializing a timer that incremented the value to display every second and sets the flag update_lcd_flag.
But when I add the pedometer code, which uses SPI1, the value on the screen never gets updated past zero. Is it because I launch a DMA interrupt from the timer interrupt, or do I need to look for problems somehwere else, e.g. in my pedometer logic or SPI1 configuration? The pedometer relies on the accelometer, which is built into STM32F4O7G-DISC1, which is my board, by default
P.S. The LCD functions don't use interrupts or DMA, they only use polling.
The timer callback
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
if (htim->Instance == TIM2) {
if (draw_ready == 1) {
HAL_GPIO_WritePin(ACC_GPIO_PORT, ACC_GPIO_PIN, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive_DMA(&hspi1, xyz_addr, xyz_data, 6);
HAL_GPIO_WritePin(ACC_GPIO_PORT, ACC_GPIO_PIN, GPIO_PIN_SET);
}
}
//else if (htim->Instance == TIM3) {
// if (draw_ready == 1) {
//steps_count += 1;
//update_lcd_flag = 1;
// }
//}
}The SPI RxTx interrupt
//spi callback function
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef * hspi)
{
if(hspi == &hspi1) {
//declare variables
int16_t x, y, z;
uint32_t mag;
uint32_t prev_index, prev_prev_index, prev_sample, prev_prev_sample;
prev_index = 0; prev_prev_index = 0; prev_sample = 0; prev_prev_sample = 0;
//calculate magnitude
x = (int16_t)((int16_t)xyz_data[0] | ((int16_t)xyz_data[1] << 8));
y = (int16_t)((int16_t)xyz_data[2] | ((int16_t)xyz_data[3] << 8));
z = (int16_t)((int16_t)xyz_data[4] | ((int16_t)xyz_data[5] << 8));
mag = (x*x + y*y + z*z); //auto-convert float to int //was sqrt
last_peak += 1; //when the last time there was a peak
value_period = 0;
prev_index = buf_index; //previous sample index
prev_prev_index = (prev_index == 0) ? (ACC_BUF_SIZE - 1) : (prev_index - 1); //(prev_index - 1) % ACC_BUF_SIZE; //pre-previous sample index
prev_sample = acc_values_buf[prev_index];
prev_prev_sample = acc_values_buf[prev_prev_index];
buf_index = (buf_index + 1) % ACC_BUF_SIZE; //update buf_index
acc_values_buf[buf_index] = mag; //add the sample
//make all checks
if ((last_peak < MAX_PEAK_DIFF && last_peak > MIN_PEAK_DIFF)
&& (prev_sample > prev_prev_sample
&& prev_sample > mag)
&& (prev_sample > PEAK_CUTOFF)) {
steps_count += 1; //uncomment later
update_lcd_flag = 1;
last_peak = 0;
}
else {
//update_lcd_flag = 0;
}
//call to SPI again //deprecated
//HAL_SPI_TransmitReceive_DMA(&hspi1, xyz_addr, xyz_data, 6);
}
}The main function
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2S3_Init();
MX_SPI1_Init();
MX_USB_HOST_Init();
MX_SPI2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
//timers
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
//Reset the screen
ILI9341_Init(&hspi2);
//screen experiment, delete later (black rectangle)
HAL_Delay(1000);
//Write_Rectangle(0, 50, 0, 50, 0, &hspi2); //good
//draw_digit(10, 10, 12, 8, 0, &hspi2); //good
//draw_number(UINT32_MAX, 12, &hspi2); //good
//Set everything for the accelometer
uint8_t OUT_X_L = 0x28;
uint8_t OUT_X_H = 0x29;
uint8_t OUT_Y_L = 0x2A;
uint8_t OUT_Y_H = 0x2B;
uint8_t OUT_Z_L = 0x2C;
uint8_t OUT_Z_H = 0x2D;
uint8_t CTRL_REG5 = 0x24; //for sensitivity (change from default 2 to 4/8) (bits 5-4)
//receivers and transmitters
xyz_addr[0] = OUT_X_L; xyz_addr[1] = OUT_X_H; xyz_addr[2] = OUT_Y_L; xyz_addr[3] = OUT_Y_H; xyz_addr[4] = OUT_Z_L; xyz_addr[5] = OUT_Z_H;
uint8_t ctrl_val;
//fill buffer with 0s
for (int i = 0; i < ACC_BUF_SIZE; i++) {
acc_values_buf[i] = 0;
}
//receive and set accelerator sensitivity
HAL_GPIO_WritePin(ACC_GPIO_PORT, ACC_GPIO_PIN, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, &CTRL_REG5, &ctrl_val, 1, 100);
HAL_GPIO_WritePin(ACC_GPIO_PORT, ACC_GPIO_PIN, GPIO_PIN_SET);
ctrl_val = ctrl_val | 0x08; //set FSCALE0
uint8_t tx_buf[2];
tx_buf[0] = CTRL_REG5 & 0x7F; //register address
tx_buf[1] = ctrl_val; //data to write into it
HAL_GPIO_WritePin(ACC_GPIO_PORT, ACC_GPIO_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, tx_buf, 2, 100);
HAL_GPIO_WritePin(ACC_GPIO_PORT, ACC_GPIO_PIN, GPIO_PIN_SET);
//initial dma call (deprecated)
//HAL_SPI_TransmitReceive_DMA(&hspi1, xyz_addr, xyz_data, 6);
//default value
//clean_screen(0xFF, &hspi2);
//draw_number(steps_count, 12, &hspi2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
uint32_t steps_count_prev = -1;
clean_screen(0xFFFF, &hspi2);
draw_ready = 1;
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();
/* USER CODE BEGIN 3 */
//During each SPI clock cycle, full-duplex transmission of a single bit occurs.
//1 clock cycle is 168/32MHz = 5.25MHz
//meaning there are 5.25 * 10^6 bit, or 5.25 * 10^6/8 bytes = 656250 bytes
//or, all coordinates are received 109375 times.
if (update_lcd_flag == 1) {
Write_Rectangle(0, 30, 0, ILI9341_WIDTH - 1, 0xFFFF, &hspi2);
draw_number(steps_count, 12, &hspi2);
update_lcd_flag = 0;
}
steps_count_prev = steps_count;
}
/* USER CODE END 3 */
}SPI1 settings
Accelometer schematic