~ruther/uni-mam-arm

a3abb3a189e245825b4c7cef2c046ffb0aefdd3b — Rutherther 4 months ago 327c9f4
feat(arm03): Update
6 files changed, 112 insertions(+), 178 deletions(-)

M arm03/include/exti.h
M arm03/include/timer.h
M arm03/src/main.c
M arm03/src/pin.c
D arm03/src/registers.c
M arm03/src/timer.c
M arm03/include/exti.h => arm03/include/exti.h +0 -2
@@ 27,8 27,6 @@ void exti_falling_interrupt(exti_t* exti);
void exti_disable_interrupt(exti_t* exti);
void exti_enable_interrupt(exti_t *exti);

void exti_nvic_setup(exti_t* exti, uint8_t line);

uint32_t exti_is_interrupt(exti_t* exti);
void exti_clear_interrupt(exti_t* exti);


M arm03/include/timer.h => arm03/include/timer.h +4 -1
@@ 4,13 4,14 @@
#define TIMER_H

typedef struct {
  TIM_TypeDef* timer;
  TIM_TypeDef* periph;
  uint8_t idx;
} timer_t;

void timer_init(timer_t* timer, TIM_TypeDef* peripheral, uint8_t timer_idx);
void timer_enable(timer_t* timer);
void timer_disable(timer_t* timer);
uint32_t timer_is_enabled(timer_t *timer);

void timer_set_refresh(timer_t* timer, uint32_t refresh_value);
void timer_set_counter(timer_t* timer, uint32_t counter);


@@ 18,6 19,8 @@ void timer_set_counter(timer_t* timer, uint32_t counter);
// TODO: rest of parameters...?
void timer_configure(timer_t* timer, uint8_t buffered_reload, uint16_t prescaler, uint8_t one_pulse_mode);

uint16_t timer_count(timer_t* timer);

void timer_enable_interrupt(timer_t* timer);
void timer_disable_interrupt(timer_t* timer);
uint32_t timer_is_interrupt(timer_t* timer);

M arm03/src/main.c => arm03/src/main.c +85 -121
@@ 4,13 4,8 @@
#include "pin.h"
#include "timer.h"
#include "registers.h"
#include "stm32f401xe.h"

#define LED_PIN 5
#define LED_GPIO GPIOA
#define BUTTON_PIN 13
#define BUTTON_GPIO GPIOC
#define BUTTON_GPIO_ID 2 // A 0 B 1 C 2
#include "display.h"
#include "delay.h"

void hard_fault_handler() {
  while(1) {}


@@ 70,143 65,112 @@ void SystemCoreClockSetHSI(void) {
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);  // Wait till PLL is system clock src
}

display_t display;

timer_t stopwatch_timer;
timer_t display_timer;

exti_t startstop_button;
exti_t null_button;

void main()
{
  // Setup
  SystemCoreClockSetHSI();
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOCEN;
  systick_configure();

  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN;
  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM1EN;

  // 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

  // Initialize timer for display at interrupt frequency
  //  digit update frequency * digits * 34
  //  aim for 100 Hz * 4 * 34 = 13 600 Hz
  //  aim for 100 Hz * 4 * 17 = 6 800 Hz

  __enable_irq();
  while(1) { __WFI(); }
}
  exti_init(&null_button, 4, EXTI, SYSCFG);
  exti_external_interrupt(&null_button, EXTI_GPIOA);
  exti_rising_interrupt(&null_button);
  exti_enable_interrupt(&null_button);

#define CYCLES 17
typedef struct {
  // Display board configuration
  uint16_t digits;
  pin_t pin_data;
  pin_t pin_sftclk;
  pin_t pin_strobe;

  // Current application data
  uint16_t number;
  uint8_t digit_dots;

  // Current application state
  uint8_t digits_en;

  // Current internal state of the display
  uint16_t current_cycle;
  uint32_t current_shifter;
  uint8_t current_digit;
  uint16_t max_value;
} display_t;

typedef enum {
  DISPLAY_UPDATE_NEW_DIGIT,
  DISPLAY_UPDATE_DISPLAY_DIGIT,
  DISPLAY_UPDATE_SHIFT,
} display_update_state_t;

const char numbers_seven_segments[11] = {
  0x3F, /* 0 */
  0x06, /* 1 */
  0x5B, /* 2 */
  0x4F, /* 3 */
  0x66, /* 4 */
  0x6D, /* 5 */
  0x7D, /* 6 */
  0x07, /* 7 */
  0x7F, /* 8 */
  0x6F, /* 9 */
  0x40, /* - */
};

/**
 * @brief Convert a digit from a regular number to seven segments
 * @param[in] number The number to convert
 * @param[in] digit The digit from least significant, starting with 0
 * @return Description
 */
uint16_t seven_segment_convert(uint16_t number, uint16_t digit);

/**
 * @brief Converts a number to serial strem to send via the SIPO register.
 * @param[in] number The number to convert to the values for shift register
 * @param[in] digit The digit from the least significant, starting with 0
 * @return Description
 */
uint16_t convert_num_digit(uint16_t number, uint8_t digit);

void display_number_set(display_t* display, uint16_t number);
void display_number_increment(display_t* display);

void display_enable_digit(display_t* display, uint8_t digit, uint8_t enable);

display_update_state_t display_update(display_t* display);

uint16_t seven_segment_convert(uint16_t number, uint16_t digit) {
  for (int i = 0; i < digit; i++) {
    number /= 10;
  exti_init(&startstop_button, 0, EXTI, SYSCFG);
  exti_external_interrupt(&startstop_button, EXTI_GPIOB);
  exti_rising_interrupt(&startstop_button);
  exti_enable_interrupt(&startstop_button);

  {
    pin_t pin_data;
    pin_t pin_sftclk;
    pin_t pin_strobe;

    pin_init(&pin_data, GPIOA, 9);
    pin_init(&pin_sftclk, GPIOA, 8);
    pin_init(&pin_strobe, GPIOB, 5);

    pin_into_output(&pin_data);
    pin_into_output(&pin_sftclk);
    pin_into_output(&pin_strobe);

    display_init(&display, 4, pin_data, pin_sftclk, pin_strobe);
    display_dots(&display, 1 << 1);
  }
  return numbers_seven_segments[number % 10];
}

uint16_t convert_num_digit(uint16_t number, uint8_t digit) {
  uint16_t seven_segments = seven_segment_convert(number, digit);
  uint16_t digits = 1 << digit;
  timer_init(&stopwatch_timer, TIM2, 2);
  timer_configure(&stopwatch_timer, 0, 60000, 0);
  timer_set_refresh(&stopwatch_timer, 10000*4);

  return (seven_segments << 8) | digits;
}
  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);

void display_number_set(display_t *display, uint16_t number) {
  display->number = number;
}
  __enable_irq();

void display_number_increment(display_t *display) {
  display->number = (display->number + 1) % display->max_value;
}
  // Application
  while (1) {
    uint32_t count = timer_count(&stopwatch_timer) >> 2;

void display_enable_digit(display_t *display, uint8_t digit, uint8_t enable) {
  uint16_t digits = 1 << digit;
  if (enable != 0) {
    display->digits_en |= digits;
  } else {
    display->digits_en &= ~digits;
    display_enable_digit(&display, 0,
                         (count % display.max_value) >= 1000);
    display_number_set(&display, count);

    /* DELAY_US(100); */
  }
}

display_update_state_t display_update(display_t *display) {
  display_update_state_t state = DISPLAY_UPDATE_SHIFT;
void null_timer(void) {
  timer_set_counter(&stopwatch_timer, 0);
}

  if (display->current_cycle == 0) {
    // Set up.
    state = DISPLAY_UPDATE_NEW_DIGIT;
void toggle_timer(void) {
  if (timer_is_enabled(&stopwatch_timer)) {
    timer_disable(&stopwatch_timer);
  } else {
    timer_enable(&stopwatch_timer);
  }
}

  if (display->current_cycle < CYCLES - 1) {
    pin_write(&display->pin_data,
              reg_read_bits_pos(&display->current_shifter,
                                16 - display->current_cycle,
                                1));

    pin_set(&display->pin_sftclk);
    pin_reset(&display->pin_sftclk);
  } else {
    // Send strobe
    pin_set(&display->pin_strobe);
    pin_reset(&display->pin_strobe);
void EXTI0_handler(void) {
  exti_clear_interrupt(&startstop_button);
  toggle_timer();
  exti_clear_interrupt(&startstop_button);
}

    state = DISPLAY_UPDATE_DISPLAY_DIGIT;
  }
void EXTI4_handler(void) {
  exti_clear_interrupt(&null_button);
  null_timer();
}

  display->current_cycle = (display->current_cycle + 1) % CYCLES;
/* void TIM1_handler(void) { */
/*   // The stopwatch timer */
/* } */

  return state;
void TIM3_handler(void) {
  timer_clear_interrupt(&display_timer);
  display_update(&display);
}

M arm03/src/pin.c => arm03/src/pin.c +2 -2
@@ 28,10 28,10 @@ void pin_toggle(pin_t *pin) {
  reg_toggle_bits_pos(&pin->gpio->ODR, pin->pin, 1);
}
void pin_set(pin_t *pin) {
  pin->gpio->ODR = 1 << pin->pin;
  pin->gpio->BSRR = 1 << pin->pin;
}
void pin_reset(pin_t *pin) {
  pin->gpio->ODR = 1 << (pin->pin + 15);
  pin->gpio->BSRR = 1 << (pin->pin + GPIO_BSRR_BR0_Pos);
}

void pin_into_output(pin_t *pin) {

D arm03/src/registers.c => arm03/src/registers.c +0 -39
@@ 1,39 0,0 @@
/* #include <stdint.h> */

/* void reg_write_bits_pos(volatile uint32_t *reg, uint32_t data, uint8_t pos, uint32_t mask) { */
/*   *reg &= ~(mask << pos); */
/*   *reg |= (data & mask) << pos; */
/* } */

/* void reg_write_bits(volatile uint32_t *reg, uint32_t data, uint32_t mask) { */
/*   *reg &= ~(mask); */
/*   *reg |= (data & mask); */
/* } */

/* void reg_set_bits_pos(volatile uint32_t *reg, uint8_t pos, uint32_t mask) { */
/*   *reg |= mask << pos; */
/* } */

/* void reg_set_bits(volatile uint32_t *reg, uint32_t mask) { */
/*   *reg |= mask; */
/* } */

/* void reg_toggle_bits_pos(volatile uint32_t *reg, uint8_t pos, uint32_t mask) { */
/*   *reg ^= (mask << pos); */
/* } */

/* void reg_toggle_bits(volatile uint32_t *reg, uint32_t mask) { */
/*   *reg ^= mask; */
/* } */

/* uint32_t reg_read_bits_pos(volatile uint32_t *reg, uint8_t pos, uint32_t mask) { */
/*   return ((*reg) >> pos) & mask; */
/* } */

/* void reg_clear_bits_pos(volatile uint32_t *reg, uint8_t pos, uint32_t mask) { */
/*   *reg ^= ~(mask << pos); */
/* } */

/* void reg_clear_bits(volatile uint32_t *reg, uint8_t pos, uint32_t mask) { */
/*   *reg &= ~mask; */
/* } */

M arm03/src/timer.c => arm03/src/timer.c +21 -13
@@ 1,32 1,40 @@
#include "timer.h"
#include "stm32f401xe.h"
#include <stm32f4xx.h>

void timer_init(timer_t *timer, TIM_TypeDef *peripheral, uint8_t timer_idx) {
  timer->timer = peripheral;
  timer->periph = peripheral;
  timer->idx = timer_idx;
}
void timer_enable(timer_t *timer) {
  timer->timer->CR1 |= TIM_CR1_CEN;
  timer->periph->CR1 |= TIM_CR1_CEN;
}
void timer_disable(timer_t *timer) {
  timer->timer->CR1 &= ~TIM_CR1_CEN;
  timer->periph->CR1 &= ~TIM_CR1_CEN;
}

uint32_t timer_is_enabled(timer_t *timer) {
  return timer->periph->CR1 & TIM_CR1_CEN;
}

void timer_set_refresh(timer_t *timer, uint32_t refresh_value) {
  timer->timer->ARR = refresh_value;
  timer->periph->ARR = refresh_value;
}
void timer_set_counter(timer_t *timer, uint32_t counter) {
  timer->timer->CNT = counter;
  timer->periph->CNT = counter;
}

uint16_t timer_count(timer_t *timer) {
  return timer->periph->CNT;
}

// TODO: rest of parameters...?
void timer_configure(timer_t *timer, uint8_t buffered_reload,
                     uint16_t prescaler, uint8_t one_pulse_mode) {
  timer->timer->CR1 = (0 << TIM_CR1_CKD_Pos) | (buffered_reload << TIM_CR1_ARPE_Pos) |
  timer->periph->CR1 = (0 << TIM_CR1_CKD_Pos) | (buffered_reload << TIM_CR1_ARPE_Pos) |
    (0 << TIM_CR1_CMS_Pos) | (0 << TIM_CR1_DIR_Pos) |
    (one_pulse_mode << TIM_CR1_OPM_Pos) | (1 << TIM_CR1_URS_Pos);
  timer->timer->CR2 = 0;
  timer->timer->PSC = prescaler - 1;
  timer->periph->CR2 = 0;
  timer->periph->PSC = prescaler - 1;
}

IRQn_Type timer_irq_idx(uint8_t line) {


@@ 48,17 56,17 @@ IRQn_Type timer_irq_idx(uint8_t line) {

void timer_enable_interrupt(timer_t *timer) {
  timer_clear_interrupt(timer);
  timer->timer->DIER |= TIM_DIER_UIE;
  timer->periph->DIER |= TIM_DIER_UIE;
  IRQn_Type irq = timer_irq_idx(timer->idx);
  NVIC_SetPriority(irq, 1);
  NVIC_EnableIRQ(irq);
}
void timer_disable_interrupt(timer_t *timer) {
  timer->timer->DIER &= ~TIM_DIER_UIE;
  timer->periph->DIER &= ~TIM_DIER_UIE;
}
uint32_t timer_is_interrupt(timer_t *timer) {
  return timer->timer->SR & TIM_SR_UIF;
  return timer->periph->SR & TIM_SR_UIF;
}
void timer_clear_interrupt(timer_t *timer) {
  timer->timer->SR = ~TIM_SR_UIF;
  timer->periph->SR = ~TIM_SR_UIF;
}

Do not follow this link