~ruther/uni-mam-arm

54e9f8d2af25b11710e86886f09b07975bd3e9cc — Rutherther 3 months ago 009a105
feat(arm07): implement most
M arm06/src/main.c => arm06/src/main.c +1 -1
@@ 221,7 221,7 @@ void main()
      }
    }

    usart_transmit(&uart, " V\r\n", 4);
    usart_transmit(&uart, " V (averaged)\r\n", 15);
  }
}


M arm07/.envrc => arm07/.envrc +1 -1
@@ 1,4 1,4 @@
use guix

# This is for clangd to work, it doesn't respect CROSS_C_INCLUDE_PATH.
export C_INCLUDE_PATH=$CROSS_C_INCLUDE_PATH
export C_INCLUDE_PATH=$CROSS_C_INCLUDE_PATH:$C_INCLUDE_PATH

M arm07/include/buffered_peripheral.h => arm07/include/buffered_peripheral.h +4 -4
@@ 8,13 8,13 @@
typedef bool (*transceiver_can_receive_t)(void* peripheral);
typedef bool (*transceiver_can_transmit_t)(void* peripheral);

typedef bool (*transceiver_receive_t)(void* peripheral, void* buffer, uint16_t max_size);
typedef bool (*transceiver_transmit_t)(void* peripheral, void* data, uint16_t size);
typedef uint16_t (*transceiver_receive_t)(void* peripheral, void* buffer, uint16_t max_size);
typedef uint16_t (*transceiver_transmit_t)(void* peripheral, void* data, uint16_t size);

typedef enum {
  OK,
  WOULD_BLOCK,
  ERROR,
  TASK_ERROR,
} task_result_t;

typedef struct {


@@ 45,6 45,6 @@ uint16_t buffered_transceiver_receive(buffered_transceiver_t* transceiver,

void buffered_transceiver_trigger_receive(buffered_transceiver_t* transceiver, uint16_t size);

void buffered_transceiver_trigger_transmit(buffered_transceiver_t* transceiver, uint16_t size);
bool buffered_transceiver_trigger_transmit(buffered_transceiver_t* transceiver, uint16_t size);

#endif // BUFFERED_PERIPHERAL_H

M arm07/include/queue.h => arm07/include/queue.h +2 -2
@@ 13,7 13,7 @@ typedef struct {
  atomic_uint_least16_t curr_write_ptr;
  atomic_uint_least16_t space;

  uint8_t elements[0];
  uint8_t* elements;
} queue_t;

/**


@@ 31,7 31,7 @@ queue_t* queue_malloc(uint16_t element_size, uint16_t length);
 * @param[in] element_size The size of one element.
 * @param[in] length The maximum number of elements.
 */
void queue_init(queue_t* queue, uint16_t element_size, uint16_t length);
void queue_init(queue_t* queue, uint16_t element_size, uint16_t length, void* data);

/**
 * @brief Enqueue the given element to the queue.

M arm07/include/spi.h => arm07/include/spi.h +8 -5
@@ 4,6 4,7 @@
#include <stm32f4xx.h>
#include <stdint.h>
#include <stdbool.h>
#include "pin.h"

typedef enum {
  SPI_FRAME_8_BIT = 0,


@@ 18,9 19,10 @@ typedef enum {
typedef struct {
  SPI_TypeDef* periph;
  uint8_t idx;
  pin_t csn;
} spi_t;

void spi_init(spi_t* spi, SPI_TypeDef* peripheral, uint8_t idx);
void spi_init(spi_t* spi, pin_t csn, SPI_TypeDef* peripheral, uint8_t idx);

void spi_master_configure_speed(spi_t *spi,
                                uint8_t divider);


@@ 29,13 31,14 @@ void spi_master_configure(spi_t *spi, bool sw_nss, bool clock_polarity,
                          bool clock_phase, spi_frame_orientation_t orientation, spi_frame_format_t format);
void spi_master_enable(spi_t* spi, bool enable);

void spi_configure_receiver(spi_t* spi, bool enable);
void spi_configure_transmitter(spi_t* spi, bool enable);

uint16_t spi_transmit(spi_t* spi, uint16_t* data, uint16_t size);
uint16_t spi_receive(spi_t *spi, uint16_t *buffer, uint16_t max_size);

bool spi_can_transmit(spi_t* spi);
bool spi_can_receive(spi_t* spi);
uint16_t spi_can_receive(spi_t* spi);

void spi_pulse_csn(spi_t *spi);

bool spi_enable_interrupt(spi_t* spi, bool tx, bool rx);

#endif // SPI_H

M arm07/include/spi_matrix.h => arm07/include/spi_matrix.h +2 -2
@@ 25,8 25,8 @@ typedef enum {
  MATRIX_REG_DECODE_MODE = 9,
  MATRIX_REG_INTENSITY = 10,
  MATRIX_REG_SCAN_LIMIT = 11,
  MATRIX_REG_SHUTDOWN = 11,
  MATRIX_REG_DISPLAY_TEST = 11,
  MATRIX_REG_SHUTDOWN = 12,
  MATRIX_REG_DISPLAY_TEST = 13,
} matrix_register_t;

typedef struct {

M arm07/include/timer.h => arm07/include/timer.h +6 -3
@@ 1,4 1,5 @@
#include <stm32f4xx.h>
#include <stdbool.h>

#ifndef TIMER_H
#define TIMER_H


@@ 33,9 34,11 @@ void timer_master_mode(timer_t* timer, timer_master_mode_t mode);

uint16_t timer_count(timer_t* timer);

void timer_enable_interrupt(timer_t* timer);
void timer_enable_interrupt(timer_t *timer, bool update, bool capture1);
void timer_disable_interrupt(timer_t* timer);
uint32_t timer_is_interrupt(timer_t* timer);
void timer_clear_interrupt(timer_t* timer);
uint32_t timer_is_update_interrupt(timer_t* timer);
uint32_t timer_is_capture1_interrupt(timer_t *timer);
void timer_clear_capture1_interrupt(timer_t* timer);
void timer_clear_update_interrupt(timer_t* timer);

#endif // TIMER_H

M arm07/include/uart.h => arm07/include/uart.h +2 -0
@@ 46,4 46,6 @@ uint16_t usart_receive(uart_t* uart, char* buffer, uint16_t max_size);
bool usart_can_transmit(uart_t* uart);
uint16_t usart_can_receive(uart_t* uart);

void usart_enable_interrupt(uart_t* uart, bool tx, bool rx);

#endif // UART_H

M arm07/picocom.sh => arm07/picocom.sh +1 -1
@@ 1,2 1,2 @@
#!/usr/bin/env bash
picocom "$1" --stopbits 1 --databits 8 --parity e --baud 9600 --echo --omap crlf
picocom "$1" --stopbits 1 --databits 8 --parity e --baud 9600 --omap crlf

M arm07/src/buffered_peripheral.c => arm07/src/buffered_peripheral.c +15 -4
@@ 1,5 1,6 @@
#include "buffered_peripheral.h"
#include <stdlib.h>
#include <string.h>

void buffered_transceiver_init(buffered_transceiver_t *transceiver,
                               queue_t *rx_queue, queue_t *tx_queue,


@@ 14,6 15,10 @@ uint16_t buffered_transceiver_transmit(buffered_transceiver_t *transceiver,
                                            void *buffer, uint16_t size) {
  uint16_t sent = 0;

  if (size == 0) {
    size = strlen((char*)buffer);
  }

  while (sent < size && queue_space(transceiver->tx_queue) > 0) {
    queue_enqueue(transceiver->tx_queue, buffer + sent * transceiver->tx_queue->element_size);
    sent++;


@@ 30,7 35,7 @@ uint16_t buffered_transceiver_receive(buffered_transceiver_t *transceiver,
  buffered_transceiver_trigger_receive(transceiver, 1);
  uint16_t received = 0;

  while (queue_count(transceiver->rx_queue) > 0) {
  while (received < max_size && queue_count(transceiver->rx_queue) > 0) {
    queue_dequeue_safely(transceiver->rx_queue, buffer + received*transceiver->rx_queue->element_size);
    received++;
  }


@@ 42,17 47,23 @@ void buffered_transceiver_trigger_receive(buffered_transceiver_t *transceiver, u
  void* element = alloca(transceiver->rx_queue->element_size);

  while (transceiver->vtable.can_receive(transceiver->peripheral) > 0 && queue_space(transceiver->rx_queue) > 0) {
    transceiver->vtable.receive(transceiver->peripheral, &element, 1);
    queue_enqueue(transceiver->rx_queue, &element);
    uint16_t received = transceiver->vtable.receive(transceiver->peripheral, element, 1);

    if (received > 0) {
      queue_enqueue(transceiver->rx_queue, element);
    }
  }
}

void buffered_transceiver_trigger_transmit(buffered_transceiver_t *transceiver,
bool buffered_transceiver_trigger_transmit(buffered_transceiver_t *transceiver,
                                           uint16_t size) {
  while (transceiver->vtable.can_transmit(transceiver->peripheral) &&
         queue_count(transceiver->tx_queue) > 0) {
    void* data = alloca(transceiver->tx_queue->element_size);
    queue_dequeue_safely(transceiver->tx_queue, data);
    transceiver->vtable.transmit(transceiver->peripheral, data, 1);
    return true;
  }

  return false;
}

M arm07/src/main.c => arm07/src/main.c +386 -116
@@ 9,7 9,9 @@
#include "display.h"
#include "delay.h"
#include "uart.h"
#include "adc.h"
#include "spi.h"
#include "buffered_peripheral.h"
#include "spi_matrix.h"

void hard_fault_handler() {
  while(1) {}


@@ 69,29 71,172 @@ void SystemCoreClockSetHSI(void) {
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);  // Wait till PLL is system clock src
}

#define DIGITS 4
#define COMMAND_SEPARATOR '\n'

#define ADC_MEASUREMENTS 16
#define LOG2_ADC_MEASUREMENTS 4
uint16_t adc_stored_values[ADC_MEASUREMENTS * 2];
// Button
pin_t user_button;
timer_t button_timer;
exti_t button_exti;

display_t display;
timer_t display_timer;
// Display
matrix_t matrix;
timer_t matrix_timer;

// SPI
pin_t spi_csn;
spi_t matrix_spi;
buffered_transceiver_t matrix_tx;
timer_t spi_csn_timer;

// Uart
uart_t uart;
adc_t adc;
timer_t adc_timer;
buffered_transceiver_t uart_rx;

#define MAX_CMD_LENGTH 65

#define AUTO_TOGGLE_CYCLES 1000000
#define MAX_IMAGES 10

uint8_t images_count = 4;
uint8_t current_image = 0;
uint8_t images[MAX_IMAGES][8] = {
    {0b11111111, 0b10000001, 0b10000001, 0b10000001, 0b10000001, 0b10000001, 0b10000001, 0b11111111},
    { 0b00000100, 0b00001110, 0b11110001, 0b10000101, 0b10000001, 0b10110001, 0b10110001, 0b11111111 },
    { 0b11111000, 0b11100100, 0b11100010, 0b10000001, 0b10000001, 0b01000010, 0b00100100, 0b00011000 },
    { 0b11000000, 0b10011000, 0b11010000, 0b10011010, 0b10010010, 0b00011010, 0b00000010, 0b00000011 },
};

uint32_t cycle = 0;
bool auto_toggle = false;
bool toggle_next = false;

bool animation = false;

void handle_command(char* cmd, uint16_t len) {
  if (len == 0) {
    return;
  }

  bool handled = false;

  switch (cmd[0]) {
  case 'n':
    // next
    if (len == 1) {
      handled = true;
      toggle_next = true;
      buffered_transceiver_transmit(&uart_rx, "Switching to next image.\r\n", 0);
    }
    break;
  case 'N':
    // auto toggle
    if (len == 1) {
      auto_toggle = !auto_toggle;

      if (auto_toggle) {
        buffered_transceiver_transmit(&uart_rx, "Going to toggle automatically.\r\n", 0);
      } else {
        buffered_transceiver_transmit(&uart_rx, "Manual switch mode.\r\n", 0);
      }
    }
    break;
  case 'a':
    // animate
    if (len == 1) {
      handled = true;
      animation = !animation;

      if (animation) {
        buffered_transceiver_transmit(&uart_rx, "Animation enabled.\r\n", 0);
      } else {
        buffered_transceiver_transmit(&uart_rx, "Animation disabled.\r\n", 0);
      }
    }
    break;
  case 'u':
    // upload
    // TODO
    break;
  case 's':
    // number of slots is...
    // TODO
    break;

  default:
    break;
  }

  if (!handled) {
    buffered_transceiver_transmit(&uart_rx, "Unknown command!\r\n", 0);
  }
}

char* receive_command(uint16_t* length)
{
  static char cmd[MAX_CMD_LENGTH];
  static uint16_t index;

  char* current_char = (cmd + index);

  while (buffered_transceiver_receive(&uart_rx, current_char, 1) == 1) {
    // echo
    buffered_transceiver_transmit(&uart_rx, current_char, 1);

typedef struct {
  char digits[4];
  uint8_t digits_count;
  uint8_t dot;
  bool error;
} converted_number_t;
    if (*current_char == COMMAND_SEPARATOR) {
      buffered_transceiver_transmit(&uart_rx, "\r", 1);
      *current_char = '\0';
      *length = index;
      index = 0;
      return cmd;
    }

    index++;
  }

  // Commands are separated either through max length, or by new line
  if (index == MAX_CMD_LENGTH + 1) {
    *length = MAX_CMD_LENGTH;
    index = 0;
    return cmd;
  }

  return NULL;
}

void next_image()
{
  current_image++;
  current_image %= images_count;

  matrix_set_buffer(&matrix, MATRIX_SLOT_OTHER, &images[current_image][0]);

  if (animation) {
    matrix_animate_swap(&matrix);
  } else {
    matrix_swap(&matrix);
  }
}

void app_loop()
{
  while (1) {
    if (auto_toggle && cycle >= AUTO_TOGGLE_CYCLES) {
      next_image();
      cycle = 0;
    } else if (toggle_next) {
      next_image();
      toggle_next = false;
    }

converted_number_t convert_number(char* data);
    uint16_t command_len;
    char* cmd = receive_command(&command_len);
    if (cmd != NULL) {
      handle_command(cmd, command_len);
    }

uint32_t averaged_adc_value = 0;
bool updated_average = 0;
    cycle++;
  }
}

void main()
{


@@ 99,45 244,37 @@ void main()
  SystemCoreClockSetHSI();
  systick_configure();

  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_DMA2EN;
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN;
  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADC1EN;
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM4EN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN;
  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2LPENR_SPI1LPEN;

  // The timer clocks are at 12 MHz.
  // For 100 Hz, the prescaler would be 120 000. That is too big,
  // so 200 Hz is chosen. From there it will have to be divided by 2 by application.
  // For 6800 Hz, 1765 prescaler will be used, leading to 6798... Hz
  { // UART init
    pin_t pin_rx;
    pin_t pin_tx;

  // Initialize timer for display at interrupt frequency
  //  digit update frequency * digits * 34
  //  aim for 100 Hz * 4 * 17 = 6 800 Hz
    #define UART_RX_BUFFER_SIZE 32
    #define UART_TX_BUFFER_SIZE 32

  {
    pin_t pin_data;
    pin_t pin_sftclk;
    pin_t pin_strobe;
    static queue_t uart_rx_queue, uart_tx_queue;
    static uint16_t uart_rx_buffer[UART_RX_BUFFER_SIZE], uart_tx_buffer[UART_TX_BUFFER_SIZE];

    pin_init(&pin_data, GPIOA, 9);
    pin_init(&pin_sftclk, GPIOA, 8);
    pin_init(&pin_strobe, GPIOB, 5);
    queue_init(&uart_rx_queue, sizeof(char), UART_RX_BUFFER_SIZE, uart_rx_buffer);
    queue_init(&uart_tx_queue, sizeof(char), UART_TX_BUFFER_SIZE, uart_tx_buffer);

    pin_into_output(&pin_data);
    pin_into_output(&pin_sftclk);
    pin_into_output(&pin_strobe);
    bool usart_generic_can_receive(void* peripheral);
    bool usart_generic_can_transmit(void* peripheral);

    display_init(&display, DIGITS, pin_data, pin_sftclk, pin_strobe);
    display_dots(&display, 1 << 0);
    uint16_t usart_generic_receive(void* peripheral, void* buffer, uint16_t max_size);
    uint16_t usart_generic_transmit(void* peripheral, void* data, uint16_t size);

    timer_init(&display_timer, TIM3, 3);
    timer_configure(&display_timer, 0, 500, 0);
    timer_set_refresh(&display_timer, 4);
    timer_enable_interrupt(&display_timer);
    timer_enable(&display_timer);
  }
    buffered_transceiver_vtable_t vtable = {
      .can_receive = usart_generic_can_receive,
      .can_transmit = usart_generic_can_transmit,
      .transmit = usart_generic_transmit,
      .receive = usart_generic_receive,
    };

  {
    pin_t pin_rx;
    pin_t pin_tx;
    buffered_transceiver_init(&uart_rx, &uart_rx_queue, &uart_tx_queue, &uart, vtable);

    pin_init(&pin_tx, GPIOA, 2);
    pin_init(&pin_rx, GPIOA, 3);


@@ 149,108 286,241 @@ void main()
    usart_configure_speed(&uart, 12000000, 9600);
    usart_configure_uart(&uart, true, USART_WORD_9_BITS, true,
                         USART_PARITY_EVEN, USART_STOP_BIT_ONE);
    usart_enable_interrupt(&uart, false, true);
    usart_configure_transmitter(&uart, true);
    usart_configure_receiver(&uart, true);
  }

  __enable_irq();
  { // SPI init
    pin_t pin_mosi;
    pin_t pin_csn;
    pin_t pin_clk;

  // Application
  while (1) {
    if (!updated_average) {
      continue;
    }
    updated_average = false;
    #define SPI_RX_BUFFER_SIZE 1
    #define SPI_TX_BUFFER_SIZE 10

    uint32_t value = averaged_adc_value;
    uint32_t voltage = (value * 3300) / 4096;
    static queue_t spi_rx_queue, spi_tx_queue;
    static uint16_t spi_rx_buffer[SPI_RX_BUFFER_SIZE], spi_tx_buffer[SPI_TX_BUFFER_SIZE];

    display_convert_number(&display, voltage);
    for (uint8_t digit = 0; digit < display.digits_count; digit++) {
      usart_transmit(&uart, &display.digits[digit], 1);
    queue_init(&spi_rx_queue, sizeof(uint16_t), SPI_RX_BUFFER_SIZE, spi_rx_buffer);
    queue_init(&spi_tx_queue, sizeof(uint16_t), SPI_TX_BUFFER_SIZE, spi_tx_buffer);

      if (digit == 0) {
        usart_transmit(&uart, ".", 1);
      }
    }
    bool spi_generic_can_receive(void* peripheral);
    bool spi_generic_can_transmit(void* peripheral);

    usart_transmit(&uart, " V\r\n", 4);
  }
}
    uint16_t spi_generic_receive(void* peripheral, void* buffer, uint16_t max_size);
    uint16_t spi_generic_transmit(void* peripheral, void* data, uint16_t size);

converted_number_t convert_number(char* data) {
  converted_number_t number;
  bool found_dot = false;
  uint8_t curr_digit = 0;
    buffered_transceiver_vtable_t vtable = {
      .can_receive = spi_generic_can_receive,
      .can_transmit = spi_generic_can_transmit,
      .transmit = spi_generic_transmit,
      .receive = spi_generic_receive,
    };

  number.dot = 0;
  number.error = false;
    buffered_transceiver_init(&matrix_tx, &spi_rx_queue, &spi_tx_queue, &matrix_spi, vtable);

  while (*data != '\0' && curr_digit < DIGITS) {
    char curr = *(data++);
    pin_init(&pin_mosi, GPIOA, 7);
    pin_init(&pin_csn, GPIOA, 4);
    pin_init(&pin_clk, GPIOB, 3);

    // handle first dot
    if (curr == '.' && !found_dot) {
      found_dot = true;
    pin_into_alternate(&pin_mosi, 5);
    /* pin_into_alternate(&pin_csn, 5); */
    pin_into_alternate(&pin_clk, 5);

      // if dot first, assume zero.
      if (curr_digit == 0) {
        number.digits[curr_digit++] = '0';
      }
    pin_set(&pin_csn);
    pin_into_output_pushpull(&pin_csn);

      number.dot = 1 << (curr_digit - 1);
      continue;
    timer_init(&spi_csn_timer, TIM4, 4);
    timer_set_refresh(&spi_csn_timer, 1);
    timer_configure(&spi_csn_timer, 0, 10000, 0);
    timer_enable_interrupt(&spi_csn_timer, true, false);

      // handle digit
    } else if (curr >= '0' && curr <= '9') {
      number.digits[curr_digit++] = curr;
    spi_init(&matrix_spi, pin_csn, SPI1, 1);
    spi_master_configure_speed(&matrix_spi, 7);
    spi_master_configure(&matrix_spi, false, false, false,
                         SPI_MSB_FIRST, SPI_FRAME_16_BIT);

      // handle others
    } else {
      number.error = true;
      break;
    }
    spi_enable_interrupt(&matrix_spi, true, false);
    spi_master_enable(&matrix_spi, true);
  }

  { // Matrix, timer init
    matrix_init(&matrix, &matrix_tx, 5);
    matrix_setup(&matrix);
    matrix_enable(&matrix, true);

    matrix_set_buffer(&matrix, MATRIX_SLOT0, images[current_image]);

    timer_init(&matrix_timer, TIM3, 3);
    timer_set_refresh(&matrix_timer, 20);
    timer_configure(&matrix_timer, 0, 60000, 0);
    timer_enable_interrupt(&matrix_timer, true, false);
    timer_enable(&matrix_timer);
  }

  if (*data != '\0') {
    number.error = true;
  { // Button, exti, timer
    pin_init(&user_button, GPIOC, 13);
    pin_into_input(&user_button);

    exti_init(&button_exti, 13, EXTI, SYSCFG);
    exti_external_interrupt(&button_exti, 2);
    exti_falling_interrupt(&button_exti);
    exti_clear_interrupt(&button_exti);
    exti_enable_interrupt(&button_exti);

    timer_init(&button_timer, TIM2, 2);
    timer_set_refresh(&button_timer, 9999);
    timer_configure(&button_timer, 0, 60000, 1);

    pin_t pin_capture;
    pin_init(&pin_capture, GPIOA, 15);
    pin_into_alternate(&pin_capture, 1);

    reg_write_bits(&button_timer.periph->CCMR1,
    //             TI1 on CCR1              no prescaler - capture every event  sampling freq = fdts / 32, N = 8
    //                                                                          fdts = 24 MHz, fsample = 750kHz
                  (1 << TIM_CCMR1_CC1S_Pos) | (0 << TIM_CCMR1_IC1PSC_Pos) | (0xF << TIM_CCMR1_IC1F_Pos),
                  TIM_CCMR1_CC1S | TIM_CCMR1_IC1PSC | TIM_CCMR1_IC1F);
    reg_write_bits(
        &button_timer.periph->CCER,
        //   enable CC1                                 falling edge captures
        (1 << TIM_CCER_CC1E_Pos) | (1 << TIM_CCER_CC1NP_Pos) | (0 << TIM_CCER_CC1P_Pos),
        TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC1NP);

    timer_enable_interrupt(&button_timer, true, true);
  }

  number.digits_count = curr_digit;
  __enable_irq();

  // Application
  app_loop();
}

void EXTI15_10_handler(void) {
  if (exti_is_interrupt(&button_exti)) {
    exti_clear_interrupt(&button_exti);

  return number;
    timer_set_counter(&button_timer, 0);
    timer_enable(&button_timer);
  }
}

/* void TIM2_handler(void) { */
/*   // The stopwatch timer */
/* } */
void TIM2_handler(void) {
  if (timer_is_update_interrupt(&button_timer)) {
    timer_clear_update_interrupt(&button_timer);
  } else if (timer_is_capture1_interrupt(&button_timer)) {
    uint32_t count = button_timer.periph->CCR1;
    timer_clear_capture1_interrupt(&button_timer);

    // 200 Hz => 5 ms
    // 50 ms is 10. That means button was really pressed by user, no bouncing
    // 2 s is 400
    if (count > 10) { // at least 50 ms
      if (count > 400) { // at least 2 s
        auto_toggle = !auto_toggle;
      } else { // less than 2 s
        if (auto_toggle) {
          auto_toggle = false;
        }
        else {
          toggle_next = true;
        }
      }

      // stop the timer
      timer_disable(&button_timer);
    }
  }
}

void TIM3_handler(void) {
  timer_clear_interrupt(&display_timer);
  display_update(&display);
  timer_clear_update_interrupt(&matrix_timer);
  matrix_update(&matrix, &matrix_tx);
}

uint32_t average_adc_values(uint16_t* buffer, uint16_t count) {
  uint32_t sum = 0;
// A flag to prevent spi communication,
// to toggle csn high
bool spi_can_transmit_flag = true;

  for (uint8_t i = 0; i < count; i++) {
    sum += buffer[i] & 0xFFF;
void SPI1_handler(void) {
  if (spi_can_receive(&matrix_spi)) {
    buffered_transceiver_trigger_receive(&matrix_tx, 1);
  }
  if (spi_can_transmit(&matrix_spi)) {
    //
    spi_can_transmit_flag = false;
    timer_set_counter(&spi_csn_timer, 0);
    timer_enable(&spi_csn_timer);

    // Disable interrupt so cpu is not locked
    spi_enable_interrupt(&matrix_spi, false, false);
  }
}

void TIM4_handler(void) {
  timer_clear_update_interrupt(&spi_csn_timer);

  if (!(matrix_spi.periph->SR & SPI_SR_BSY)) {
    // disable and enable spi so that CSN is pulsed.
    spi_pulse_csn(&matrix_spi);

  return sum >> LOG2_ADC_MEASUREMENTS;
    // Allow sending...
    spi_can_transmit_flag = true;

    // Disable this timer until transmission is done again
    timer_disable(&spi_csn_timer);

    // Transmit only after the pulse. SPI is enabled again.
    buffered_transceiver_trigger_transmit(&matrix_tx, 1);

  }
}

void DMA2_Stream0_handler(void) {
  if (DMA2->LISR & DMA_LISR_HTIF0) {
    DMA2->LIFCR = DMA_LIFCR_CHTIF0;
    averaged_adc_value = average_adc_values(adc_stored_values, ADC_MEASUREMENTS);
  } else if (DMA2->LISR & DMA_LISR_TCIF0) {
    DMA2->LIFCR = DMA_LIFCR_CTCIF0;
    averaged_adc_value = average_adc_values(adc_stored_values + ADC_MEASUREMENTS, ADC_MEASUREMENTS);
void USART2_handler(void) {
  if (usart_can_receive(&uart)) {
    buffered_transceiver_trigger_receive(&uart_rx, 1);
  }
  if (usart_can_transmit(&uart)) {
    if (!buffered_transceiver_trigger_transmit(&uart_rx, 1)) {
      usart_enable_interrupt(&uart, false, true);
    }
  }
  updated_average = true;
}

void SPI1_handler(void) {

bool spi_generic_can_receive(void *peripheral) {
  return spi_can_receive((spi_t*)peripheral);
}
bool spi_generic_can_transmit(void *peripheral) {
  return spi_can_transmit_flag && (((spi_t*)peripheral)->periph->SR & SPI_SR_BSY) == 0;
}

uint16_t spi_generic_receive(void *peripheral, void *buffer,
                             uint16_t max_size) {
  return spi_receive((spi_t*)peripheral, buffer, max_size);
}
uint16_t spi_generic_transmit(void *peripheral, void *data, uint16_t size) {
  // enable the interrupt so that we can send the rest
  uint16_t ret = spi_transmit((spi_t*)peripheral, data, size);
  spi_enable_interrupt((spi_t*)peripheral, true, false);
  return ret;
}

bool usart_generic_can_receive(void *peripheral) {
  return usart_can_receive((uart_t*)peripheral);
}
bool usart_generic_can_transmit(void *peripheral) {
  return usart_can_transmit((uart_t*)peripheral);
}

uint16_t usart_generic_receive(void *peripheral, void *buffer,
                             uint16_t max_size) {
  return usart_receive((uart_t*)peripheral, buffer, max_size);
}
uint16_t usart_generic_transmit(void *peripheral, void *data, uint16_t size) {
  uint16_t ret = usart_transmit((uart_t*)peripheral, data, size);
  // enable the interrupt so that we can send the rest
  usart_enable_interrupt((uart_t*)peripheral, true, true);
  return ret;
}

M arm07/src/queue.c => arm07/src/queue.c +2 -1
@@ 5,12 5,13 @@ queue_t *queue_malloc(uint16_t element_size, uint16_t length) {
  return (queue_t*)malloc(sizeof(queue_t) + element_size * length);
}

void queue_init(queue_t* queue, uint16_t element_size, uint16_t length) {
void queue_init(queue_t* queue, uint16_t element_size, uint16_t length, void* data) {
  queue->curr_write_ptr = 0;
  queue->curr_read_ptr = 0;
  queue->element_size = element_size;
  queue->length = length;
  queue->space = length;
  queue->elements = data;
}

bool queue_enqueue(queue_t *queue, void *element) {

M arm07/src/spi.c => arm07/src/spi.c +29 -12
@@ 1,9 1,11 @@
#include "spi.h"
#include "registers.h"
#include "stm32f401xe.h"

void spi_init(spi_t* spi, SPI_TypeDef* peripheral, uint8_t idx) {
void spi_init(spi_t* spi, pin_t csn, SPI_TypeDef* peripheral, uint8_t idx) {
  spi->periph = peripheral;
  spi->idx = idx;
  spi->csn = csn;
}

void spi_master_configure_speed(spi_t *spi,


@@ 16,20 18,22 @@ void spi_master_configure(spi_t *spi, bool sw_nss, bool clock_polarity,
  reg_write_bits(&spi->periph->CR1,
                 (sw_nss << SPI_CR1_SSM_Pos) | (format << SPI_CR1_DFF_Pos) |
                     (orientation << SPI_CR1_LSBFIRST_Pos) |
                     (1 << SPI_CR1_BIDIMODE_Pos) | (1 << SPI_CR1_MSTR_Msk) |
                 (clock_polarity << SPI_CR1_CPOL_Msk) | (clock_phase << SPI_CR1_CPHA_Msk),
                     (0 << SPI_CR1_BIDIMODE_Pos) | (1 << SPI_CR1_MSTR_Pos) |
                 (clock_polarity << SPI_CR1_CPOL_Pos) | (clock_phase << SPI_CR1_CPHA_Pos),
                 SPI_CR1_SSM_Msk | SPI_CR1_DFF_Msk | SPI_CR1_LSBFIRST_Msk | SPI_CR1_BIDIMODE_Msk | SPI_CR1_MSTR_Msk | SPI_CR1_CPOL_Msk | SPI_CR1_CPHA_Msk);

  spi->periph->CR2 |= SPI_CR2_SSOE | (1 << 3);
}
void spi_master_enable(spi_t *spi, bool enable) {
  reg_set_bits(&spi->periph->CR1, SPI_CR1_SPE);
  reg_write_bits(&spi->periph->CR1, enable << SPI_CR1_SPE_Pos, SPI_CR1_SPE);
}

uint16_t spi_transmit(spi_t *spi, uint16_t *data, uint16_t size) {
  pin_reset(&spi->csn);
  for (int16_t i = 0; i < size; i++) {
    char byte = *(data++);

    while (!(spi->periph->SR & USART_SR_TXE));
    spi->periph->DR = byte;
    while (!(spi->periph->SR & SPI_SR_TXE));
    uint16_t word = *(data++);
    spi->periph->DR = word;
  }

  return size;


@@ 37,18 41,31 @@ uint16_t spi_transmit(spi_t *spi, uint16_t *data, uint16_t size) {
uint16_t spi_receive(spi_t *spi, uint16_t *buffer, uint16_t max_size) {
  uint16_t size = 0;

  while (size < max_size - 1 && (spi->periph->SR & USART_SR_RXNE)) {
    *(buffer + (size++)) = (char)(spi->periph->DR & USART_DR_DR_Msk);
  while (size < max_size && (spi->periph->SR & SPI_SR_RXNE)) {
    *(buffer + (size++)) = (char)(spi->periph->DR & SPI_DR_DR_Msk);
  }

  return size;

}

void spi_pulse_csn(spi_t *spi) {
  pin_set(&spi->csn);
}

bool spi_can_transmit(spi_t *spi) {
  return (spi->periph->SR & SPI_SR_TXE) != 0;
}
bool spi_can_receive(spi_t *spi) {
  return (spi->periph->SR & SPI_SR_RXNE) != 0;
uint16_t spi_can_receive(spi_t *spi) {
  return ((spi->periph->SR & SPI_SR_RXNE) != 0) ? 1 : 0;
}

bool spi_enable_interrupt(spi_t *spi, bool tx, bool rx) {
  reg_write_bits(&spi->periph->CR2,
                 (tx << SPI_CR2_TXEIE_Pos) | (rx << SPI_CR2_RXNEIE_Pos),
                 SPI_CR2_TXEIE | SPI_CR2_RXNEIE);

  // TODO: proper irq by idx
  NVIC_SetPriority(SPI1_IRQn, 1);
  NVIC_EnableIRQ(SPI1_IRQn);
}

M arm07/src/spi_matrix.c => arm07/src/spi_matrix.c +15 -2
@@ 6,6 6,11 @@ void matrix_init(matrix_t *matrix, buffered_transceiver_t *transceiver,
                 uint32_t shift_period) {
  matrix->transceiver = transceiver;
  matrix->shift_period = shift_period;
  matrix->slot = MATRIX_SLOT0;
  matrix->state = MATRIX_OFF;

  matrix->state_cycle = 0;
  matrix->cycle = 0;
}

void matrix_setup(matrix_t *matrix) {


@@ 16,6 21,11 @@ void matrix_setup(matrix_t *matrix) {
void matrix_enable(matrix_t *matrix, bool enable) {
  matrix->state = MATRIX_STABLE;
  matrix->slot = MATRIX_SLOT0;

  matrix_send(matrix, MATRIX_REG_SHUTDOWN, enable ? 1 : 0);
  matrix_send(matrix, MATRIX_REG_DECODE_MODE, 0);
  matrix_send(matrix, MATRIX_REG_INTENSITY, 0x01);
  matrix_send(matrix, MATRIX_REG_SCAN_LIMIT, 0x7);
}

void matrix_send(matrix_t *matrix, matrix_register_t reg, uint8_t value) {


@@ 45,9 55,9 @@ void matrix_swap(matrix_t *matrix) {
}

void matrix_animate_swap(matrix_t *matrix) {
  matrix->state = MATRIX_ANIMATING;
  matrix->state_cycle = 0;
  matrix->cycle = 0;
  matrix->state = MATRIX_ANIMATING;
}

void matrix_update(matrix_t *matrix, buffered_transceiver_t *transceiver) {


@@ 60,12 70,13 @@ void matrix_update(matrix_t *matrix, buffered_transceiver_t *transceiver) {
    for (uint8_t digit = 0; digit < DIGITS; digit++) {
      matrix_send(matrix, MATRIX_REG_DIGIT0 + digit, 0);
    }

    break;
  case MATRIX_STABLE:
    // send all digits
    for (uint8_t digit = 0; digit < DIGITS; digit++) {
      matrix_send(matrix, MATRIX_REG_DIGIT0 + digit, buffer[digit]);
    }
    break;
  case MATRIX_ANIMATING:
    // update the cycle
    matrix->cycle++;


@@ 76,6 87,7 @@ void matrix_update(matrix_t *matrix, buffered_transceiver_t *transceiver) {

    if (matrix->state_cycle == DIGITS) {
      matrix->state = MATRIX_STABLE;
      matrix_swap(matrix);
    }

    for (uint8_t digit = 0; digit < DIGITS - matrix->state_cycle; digit++) {


@@ 85,5 97,6 @@ void matrix_update(matrix_t *matrix, buffered_transceiver_t *transceiver) {
    for (uint8_t digit = DIGITS - matrix->state_cycle; digit < DIGITS; digit++) {
      matrix_send(matrix, MATRIX_REG_DIGIT0 + digit, other_buffer[digit - (DIGITS - matrix->state_cycle)]);
    }
    break;
  }
}

M arm07/src/timer.c => arm07/src/timer.c +23 -5
@@ 60,19 60,37 @@ IRQn_Type timer_irq_idx(uint8_t line) {
  }
}

void timer_enable_interrupt(timer_t *timer) {
  timer_clear_interrupt(timer);
  timer->periph->DIER |= TIM_DIER_UIE;
void timer_enable_interrupt(timer_t *timer, bool update, bool capture1) {
  timer_clear_update_interrupt(timer);
  timer_clear_capture1_interrupt(timer);
  if (update) {
    timer->periph->DIER |= TIM_DIER_UIE;
  }
  if (capture1) {
    timer->periph->DIER |= TIM_DIER_CC1IE;
  }
  IRQn_Type irq = timer_irq_idx(timer->idx);
  NVIC_SetPriority(irq, 1);
  NVIC_EnableIRQ(irq);
}

void timer_disable_interrupt(timer_t *timer) {
  timer->periph->DIER &= ~TIM_DIER_UIE;
  timer->periph->DIER &= ~TIM_DIER_CC1IE;
}
uint32_t timer_is_interrupt(timer_t *timer) {

uint32_t timer_is_update_interrupt(timer_t *timer) {
  return timer->periph->SR & TIM_SR_UIF;
}
void timer_clear_interrupt(timer_t *timer) {

uint32_t timer_is_capture1_interrupt(timer_t *timer) {
  return timer->periph->SR & TIM_SR_CC1IF;
}

void timer_clear_update_interrupt(timer_t *timer) {
  timer->periph->SR = ~TIM_SR_UIF;
}

void timer_clear_capture1_interrupt(timer_t *timer) {
  timer->periph->SR = ~TIM_SR_CC1IF;
}

M arm07/src/uart.c => arm07/src/uart.c +19 -3
@@ 46,9 46,8 @@ void usart_configure_transmitter(uart_t* uart, bool enable) {

uint16_t usart_transmit(uart_t *uart, char *data, uint16_t size) {
  for (int16_t i = 0; i < size; i++) {
    char byte = *(data++);

    while (!(uart->periph->SR & USART_SR_TXE));
    char byte = *(data++);
    uart->periph->DR = byte;
  }



@@ 58,9 57,26 @@ uint16_t usart_transmit(uart_t *uart, char *data, uint16_t size) {
uint16_t usart_receive(uart_t* uart, char *buffer, uint16_t max_size) {
  uint16_t size = 0;

  while (size < max_size - 1 && (uart->periph->SR & USART_SR_RXNE)) {
  while (size < max_size && (uart->periph->SR & USART_SR_RXNE)) {
    *(buffer + (size++)) = (char)(uart->periph->DR & USART_DR_DR_Msk);
  }

  return size;
}

bool usart_can_transmit(uart_t* uart) {
  return uart->periph->SR & USART_SR_TXE;
}
uint16_t usart_can_receive(uart_t* uart) {
  return ((uart->periph->SR & USART_SR_RXNE) != 0) ? 1 : 0;
}

void usart_enable_interrupt(uart_t *uart, bool tx, bool rx) {
  reg_write_bits(&uart->periph->CR1,
                 (tx << USART_CR1_TXEIE_Pos) | (rx << USART_CR1_RXNEIE_Pos),
                 USART_CR1_TXEIE | USART_CR1_RXNEIE);

  // TODO: proper irq by idx
  NVIC_SetPriority(USART2_IRQn, 1);
  NVIC_EnableIRQ(USART2_IRQn);
}

Do not follow this link