aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c167
1 files changed, 165 insertions, 2 deletions
diff --git a/src/main.c b/src/main.c
index 4726e5e..241f369 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,11 +1,174 @@
-#define PINOUT_BTN (8)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stm32f091xc.h"
+
+// GPIO A
+#define PINOUT_DISP_CLK (5)
+#define PINOUT_DISP_DIO (6)
+#define PINOUT_POT (7)
+
+// GPIO B
#define PINOUT_LED_1 (3)
#define PINOUT_LED_2 (5)
#define PINOUT_LED_3 (4)
#define PINOUT_LED_4 (6)
+
const unsigned short leds[] = {PINOUT_LED_1, PINOUT_LED_2, PINOUT_LED_3, PINOUT_LED_4};
+#define PINOUT_BTN (8)
+
+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_DISP_CLK * 2)) |
+ (0b11 << (PINOUT_DISP_DIO * 2)) |
+ (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 |= (0b01 << (PINOUT_DISP_CLK * 2)) |
+ (0b01 << (PINOUT_DISP_DIO * 2)) |
+ (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;
+ return;
+}
+
+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.
+ */
+int 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() {
- return 0;
+ shield_config();
+ interrupt_setup();
+
+ while (1) {
+ // if ((TIM3->SR & TIM_SR_CC1IF) > 0) {
+ // toggle_direction();
+ // TIM3->CNT = 0;
+ // TIM3->SR &= ~(TIM_SR_CC1IF);
+ // TIM3->EGR |= TIM_EGR_UG;
+ // }
+ timer_delay(100);
+ next_led();
+ }
+}
+
+#ifdef __cplusplus
}
+#endif