diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..7978b16 --- /dev/null +++ b/src/main.c @@ -0,0 +1,162 @@ +#include <stdbool.h> +#include "stm32f091xc.h" +#include "main.h" +#include "tm1637.h" + +const unsigned short leds[] = {PINOUT_LED_1, PINOUT_LED_2, PINOUT_LED_3, PINOUT_LED_4}; +volatile bool led_direction = false; + +/* + * This function configures the I/O-ports that are used by the I/O-shield. It + * uses register RCC_AHBENR to enable the clocks for the ports that are used, + * register GPIOx_MODER to configure pins as input, analog or output and + * GPIOx_PUPDR to configure pull-up and pull-down resistors. + */ +void shield_config() { + // enable internal clocks + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // GPIO A and B + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // ADC1 peripheral + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // TIM3 + + // clear mode register configuration bits + GPIOB->MODER &= ~((0b11 << (PINOUT_LED_1 * 2)) | + (0b11 << (PINOUT_LED_2 * 2)) | + (0b11 << (PINOUT_LED_3 * 2)) | + (0b11 << (PINOUT_LED_4 * 2)) | + (0b11 << (PINOUT_BTN * 2))); + GPIOA->MODER &= ~(0b11 << (PINOUT_POT * 2)); + + // set output mode register configuration bits + // 0b00 -> input mode (reset state) + // 0b01 -> general purpose output mode + // 0b10 -> alternate function mode + // 0b11 -> analog mode + GPIOB->MODER |= (0b01 << (PINOUT_LED_1 * 2)) | + (0b01 << (PINOUT_LED_2 * 2)) | + (0b01 << (PINOUT_LED_3 * 2)) | + (0b01 << (PINOUT_LED_4 * 2)) | + (0b00 << (PINOUT_BTN * 2)); + GPIOA->MODER |= (0b11 << (PINOUT_POT * 2)); + + // pull-up resistor for button + GPIOB->PUPDR &= ~(0b11 << (PINOUT_BTN * 2)); + GPIOB->PUPDR |= (0b01 << (PINOUT_BTN * 2)); + + // calirate ADC1 + ADC1->CR |= ADC_CR_ADCAL; + while (ADC1->CR & ADC_CR_ADCAL); + ADC1->CR |= ADC_CR_ADEN; // enable ADC1 + + // TIM3 setup + TIM3->PSC = 8000 - 1; // prescaler set so each timer tick is 1ms + TIM3->CCMR1 |= TIM_CCMR1_OC1M_0; + TIM3->EGR |= TIM_EGR_UG; // generate update event + TIM3->CR1 |= TIM_CR1_CEN; // enable counter +} + + +void toggle_direction() { + led_direction = !led_direction; +} + +void EXTI4_15_IRQHandler(void) { + // toggle_direction(); + led_direction = !led_direction; +} + +void interrupt_setup() { + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; + // RCC->APB2ENR |= RCC_APB2ENR_SYSCFGCOMPEN; + SYSCFG->EXTICR[PINOUT_BTN / 4] &= ~(0xF << ((PINOUT_BTN % 4) * 4)); + SYSCFG->EXTICR[PINOUT_BTN / 4] |= (0x1 << ((PINOUT_BTN % 4) * 4)); + + EXTI->IMR |= (1 << PINOUT_BTN); + EXTI->RTSR &= ~(1 << PINOUT_BTN); + EXTI->FTSR |= (1 << PINOUT_BTN); + + NVIC_SetPriority(EXTI4_15_IRQn, 3); + NVIC_EnableIRQ(EXTI4_15_IRQn); +} + +/* + * This function drives led <num> of the I/O-shield. <num> should be the number + * of the LED to drive (0, 1, 2 or 3) and <on> should be an integer with value + * 0 or 1 which indicates if the LED should be turned on (1) or off (0). + */ +void led_write(int num, int on) { + GPIOB->ODR &= ~(1 << leds[num]); + GPIOB->ODR |= (on << leds[num]); +} + +/* + * This function returns the status of the pushbutton of the I/O-shield. + * Return value 1 indicates that the button is currently pressed and return + * value 0 indicates that the button is currently not pressed. + */ +int button_read() { + return (GPIOB->IDR & (1 << PINOUT_BTN)) == 0; +} + +/* + * Read potmeter value as analog value between 0 and 2^12 - 1 + */ +unsigned int pot_read() { + ADC1->CHSELR = (1 << PINOUT_POT); + ADC1->CR |= ADC_CR_ADSTART; + while (ADC1->CR & ADC_CR_ADSTART); + uint16_t result = ADC1->DR; + ADC1->CR |= ADC_CR_ADSTP; + return result; +} + +void next_led() { + static uint8_t led = 0; + for(int j = 0; j < 4; j++) led_write(j, 0); // clear all leds + led = (led + led_direction * 2 - 1) & 0b11; // calculate next led index + led_write(led, 1); +} + +void dumb_delay() { + for(unsigned long i = 0; i < 50e3; i++); +} + +/** + * This function uses timer 3 to generate a blocking delay of <milliseconds>. + * It uses the channel 1 capture/compare register to check if the time (in + * milliseconds) has expired. + */ +void timer_delay(unsigned short millis) { + TIM3->CCR1 = millis; // set delay amount + TIM3->CNT = 0; // reset timer + TIM3->SR &= ~(TIM_SR_CC1IF); // reset capture/compare output + while ((TIM3->SR & TIM_SR_CC1IF) == 0); // wait until c/c goes high +} + +int main() { + shield_config(); + tm1637_begin(); + timer_delay(2000); + + unsigned int minutes = 0; + unsigned int seconds = 0; + + TM1637Sequence seq; + uint8_t dis_br_data[] = { 0b10001111 }; + seq.data = dis_br_data; + seq.length = 1; + _tm1637_send(seq); + + uint8_t dis_seg_data[] = { 0b11000001, 0b01111111 }; + seq.data = dis_seg_data; + seq.length = 2; + _tm1637_send(seq); + + while (1) { + timer_delay(1e3); + seconds++; + if (seconds >= 60) { + seconds = 0; + minutes++; + } + } +} |