Skip to content

Instantly share code, notes, and snippets.

@geolessel
Last active June 23, 2020 21:38
Show Gist options
  • Save geolessel/9c29381fef1f80a79afa74d1a818a646 to your computer and use it in GitHub Desktop.
Save geolessel/9c29381fef1f80a79afa74d1a818a646 to your computer and use it in GitHub Desktop.
/****************************************************************************\
File: main.c
Date: 2020-06-22
Description:
Detect the edge of a button/switch on PortA Pin 2. Use that to toggle the
output of PortC Pin 13 (onboard LED).
USED PORTS:
- A2 (button input)
- C13 (onboard LED)
Known bugs/missing features:
\****************************************************************************/
#include <stdint.h>
#include "main.h"
void setup_clock(void);
void setup_gpio(void);
volatile char led_on = 0;
#ifndef DO_IT
#error "This code doesn't work. To compile anyway, set DO_IT (make CFLAGS='-DDO_IT')."
#endif
int main(void) {
setup_clock();
setup_gpio();
// Port C output data register (GPIOC_ODR; datasheet 9.2.4)
GPIOX_ODR_t volatile *const pGPIOCOutputDataRegister = GPIOC_ODR;
while(1) {
if (led_on) {
// LED is active low
pGPIOCOutputDataRegister->odr13 = PIN_LOW;
} else {
pGPIOCOutputDataRegister->odr13 = PIN_HIGH;
}
for(uint32_t i = 0; i < 200000; i++);
led_on = !led_on;
}
}
void setup_clock() {
// Configure clock to be HSE
RCC_CR_t volatile *const pClockControlRegister = RCC_CR;
pClockControlRegister->hse_on = ENABLE;
// Wait for the HSE oscillator to stabilize
while(!pClockControlRegister->hse_rdy);
// PLL multiplier must be set before PLL is enabled
// I CANT GET THE LED TO FLASH ABOVE 24MHZ (pll_mul 0b0001 8MHz x3)
RCC_CFGR_t volatile *const pClockConfigurationRegister = RCC_CFGR;
pClockConfigurationRegister->sw = 0b10;
// divide every peripheral as much as possible
pClockConfigurationRegister->adc_pre = 0b11;
pClockConfigurationRegister->p_pre1 = 0b111;
pClockConfigurationRegister->p_pre2 = 0b111;
// 0b0000 x2
// 0b0001 x3
// 0b0010 x4
// 0b0011 x5
// 0b0100 x6
// 0b0101 x7
// 0b0110 x8
pClockConfigurationRegister->pll_mul = 0b0110;
pClockConfigurationRegister->pll_src = 0b1;
while(pClockControlRegister->pll_rdy);
// set flash latency for higher speed clock (3.3.3)
FLASH_ACR_t volatile *const pFlashAccessControlRegister = FLASH_ACR;
// 00 < SYSCLK <= 24MHz 0b000
// 24 < SYSCLK <= 48MHz 0b001
// 48 < SYSCLK <= 72MHz 0b010
pFlashAccessControlRegister->latency = 0b010;
pClockControlRegister->pll_on = ENABLE;
while(!pClockControlRegister->pll_rdy);
// Configure SYSCLOCK to be PLL
pClockConfigurationRegister->sw = 0b10;
RCC_APB2ENR_t volatile *const pApb2ClockControlRegister = RCC_APB2ENR;
// Enable the clock for PORT C
pApb2ClockControlRegister->iopcen = ENABLE;
}
void setup_gpio() {
GPIOX_CRH_t volatile *const pGPIOCModeRegister = GPIOC_CRH;
// Configure PORT C13 as output (onboard LED)
pGPIOCModeRegister->cnf13 = GPIO_CNF_OUTPUT_PUSH_PULL;
pGPIOCModeRegister->mode13 = GPIO_MODE_OUTPUT_2MHZ;
}
#ifndef MAIN_H_
#define MAIN_H_
#include <stdint.h>
#define PERIPHERAL_ADDR_OFFSET (0x40000000ul)
#define GPIOX_CRL_OFFSET (0x00ul)
#define GPIOX_CRH_OFFSET (0x04ul)
#define GPIOX_IDR_OFFSET (0x08ul)
#define GPIOX_ODR_OFFSET (0x0Cul)
#define GPIOX_BSRR_OFFSET (0x10ul)
#define GPIOX_BRR_OFFSET (0x14ul)
#define GPIOX_LCKR_OFFSET (0x18ul)
#define PORTA_ADDR_OFFSET (0x40010800ul)
#define PORTA_CRL_ADDR (PORTA_ADDR_OFFSET + GPIOX_CRL_OFFSET)
#define PORTA_CRH_ADDR (PORTA_ADDR_OFFSET + GPIOX_CRH_OFFSET)
#define PORTA_IDR_ADDR (PORTA_ADDR_OFFSET + GPIOX_IDR_OFFSET)
#define PORTA_ODR_ADDR (PORTA_ADDR_OFFSET + GPIOX_ODR_OFFSET)
#define PORTA_BSRR_ADDR (PORTA_ADDR_OFFSET + GPIOX_BSRR_OFFSET)
#define PORTA_BRR_ADDR (PORTA_ADDR_OFFSET + GPIOX_BRR_OFFSET)
#define PORTA_LCKR_ADDR (PORTA_ADDR_OFFSET + GPIOX_LCKR_OFFSET)
#define PORTB_ADDR_OFFSET (0x40010C00ul)
#define PORTB_CRL_ADDR (PORTB_ADDR_OFFSET + GPIOX_CRL_OFFSET)
#define PORTB_CRH_ADDR (PORTB_ADDR_OFFSET + GPIOX_CRH_OFFSET)
#define PORTB_IDR_ADDR (PORTB_ADDR_OFFSET + GPIOX_IDR_OFFSET)
#define PORTB_ODR_ADDR (PORTB_ADDR_OFFSET + GPIOX_ODR_OFFSET)
#define PORTB_BSRR_ADDR (PORTB_ADDR_OFFSET + GPIOX_BSRR_OFFSET)
#define PORTB_BRR_ADDR (PORTB_ADDR_OFFSET + GPIOX_BRR_OFFSET)
#define PORTB_LCKR_ADDR (PORTB_ADDR_OFFSET + GPIOX_LCKR_OFFSET)
#define PORTC_ADDR_OFFSET (0x40011000ul)
#define PORTC_CRL_ADDR (PORTC_ADDR_OFFSET + GPIOX_CRL_OFFSET)
#define PORTC_CRH_ADDR (PORTC_ADDR_OFFSET + GPIOX_CRH_OFFSET)
#define PORTC_IDR_ADDR (PORTC_ADDR_OFFSET + GPIOX_IDR_OFFSET)
#define PORTC_ODR_ADDR (PORTC_ADDR_OFFSET + GPIOX_ODR_OFFSET)
#define PORTC_BSRR_ADDR (PORTC_ADDR_OFFSET + GPIOX_BSRR_OFFSET)
#define PORTC_BRR_ADDR (PORTC_ADDR_OFFSET + GPIOX_BRR_OFFSET)
#define PORTC_LCKR_ADDR (PORTC_ADDR_OFFSET + GPIOX_LCKR_OFFSET)
#define RCC_ADDR_OFFSET (0x40021000ul)
#define RCC_CR_ADDR (RCC_ADDR_OFFSET + 0x00ul)
#define RCC_CFGR_ADDR (RCC_ADDR_OFFSET + 0x04ul)
#define RCC_APB2ENR_ADDR (RCC_ADDR_OFFSET + 0x18ul)
// this address is specific to medium-density devices
#define FLASH_MEMORY_INTERFACE_REGISTERS_ADDR (0x40022000ul)
#define FLASH_ACR_ADDR (FLASH_MEMORY_INTERFACE_REGISTERS_ADDR + 0x00ul)
#define EXTI_ADDR_OFFSET (0x40010400ul)
#define EXTI_IMR_ADDR (EXTI_ADDR_OFFSET + 0x00ul)
#define EXTI_EMR_ADDR (EXTI_ADDR_OFFSET + 0x04ul)
#define EXTI_RTSR_ADDR (EXTI_ADDR_OFFSET + 0x08ul)
#define EXTI_FTSR_ADDR (EXTI_ADDR_OFFSET + 0x0Cul)
#define EXTI_SWIER_ADDR (EXTI_ADDR_OFFSET + 0x10ul)
#define EXTI_PR_ADDR (EXTI_ADDR_OFFSET + 0x14ul)
#define AFIO_ADDR_OFFSET (0x40010000ul)
#define AFIO_EVCR_ADDR (AFIO_ADDR_OFFSET + 0x00ul)
#define AFIO_MAPR_ADDR (AFIO_ADDR_OFFSET + 0x04ul)
#define AFIO_EXTICR1_ADDR (AFIO_ADDR_OFFSET + 0x08ul)
#define AFIO_EXTICR2_ADDR (AFIO_ADDR_OFFSET + 0x0Cul)
#define AFIO_EXTICR3_ADDR (AFIO_ADDR_OFFSET + 0x10ul)
#define AFIO_EXTICR4_ADDR (AFIO_ADDR_OFFSET + 0x14ul)
#define AFIO_MAPR2_ADDR (AFIO_ADDR_OFFSET + 0x1Cul)
#define RCC_CR ((RCC_CR_t *) RCC_CR_ADDR)
#define RCC_CFGR ((RCC_CFGR_t *) RCC_CFGR_ADDR)
#define RCC_APB2ENR ((RCC_APB2ENR_t *) RCC_APB2ENR_ADDR)
#define FLASH_ACR ((FLASH_ACR_t *) FLASH_ACR_ADDR)
// 9.2
#define GPIOA_CRL ((GPIOX_CRL_t *) PORTA_CRL_ADDR)
#define GPIOA_CRH ((GPIOX_CRH_t *) PORTA_CRH_ADDR)
#define GPIOA_IDR ((GPIOX_IDR_t *) PORTA_IDR_ADDR)
#define GPIOA_ODR ((GPIOX_ODR_t *) PORTA_ODR_ADDR)
#define GPIOB_CRL ((GPIOX_CRL_t *) PORTB_CRL_ADDR)
#define GPIOB_CRH ((GPIOX_CRH_t *) PORTB_CRH_ADDR)
#define GPIOB_IDR ((GPIOX_IDR_t *) PORTB_IDR_ADDR)
#define GPIOB_ODR ((GPIOX_ODR_t *) PORTB_ODR_ADDR)
#define GPIOC_CRL ((GPIOX_CRL_t *) PORTC_CRL_ADDR)
#define GPIOC_CRH ((GPIOX_CRH_t *) PORTC_CRH_ADDR)
#define GPIOC_IDR ((GPIOX_IDR_t *) PORTC_IDR_ADDR)
#define GPIOC_ODR ((GPIOX_ODR_t *) PORTC_ODR_ADDR)
// 9.4
#define AFIO_EVCR ((AFIO_EVCR_t *) AFIO_EVCR_ADDR)
#define AFIO_MAPR ((AFIO_MAPR_t *) AFIO_MAPR_ADDR)
#define AFIO_EXTICR1 ((AFIO_EXTICR1_t *) AFIO_EXTICR1_ADDR)
#define AFIO_EXTICR2 ((AFIO_EXTICR2_t *) AFIO_EXTICR2_ADDR)
#define AFIO_EXTICR3 ((AFIO_EXTICR3_t *) AFIO_EXTICR3_ADDR)
#define AFIO_EXTICR4 ((AFIO_EXTICR4_t *) AFIO_EXTICR4_ADDR)
// 10.3
#define EXTI_IMR ((EXTI_IMR_t *) EXTI_IMR_ADDR)
#define EXTI_EMR ((EXTI_EMR_t *) EXTI_EMR_ADDR)
#define EXTI_RTSR ((EXTI_RTSR_t *) EXTI_RTSR_ADDR)
#define EXTI_FTSR ((EXTI_FTSR_t *) EXTI_FTSR_ADDR)
#define EXTI_SWIER ((EXTI_SWIER_t *) EXTI_SWIER_ADDR)
#define EXTI_PR ((EXTI_PR_t *) EXTI_PR_ADDR)
#define ENABLE (1)
#define DISABLE (0)
#define CLOCK_ENABLE (1)
#define PIN_LOW (0)
#define PIN_HIGH (1)
// 9.2.2
#define GPIO_CNF_INPUT_ANALOG (0b00)
#define GPIO_CNF_INPUT_FLOATING (0b01)
#define GPIO_CNF_INPUT (0b10)
#define GPIO_CNF_OUTPUT_PUSH_PULL (0b00)
#define GPIO_CNF_OUTPUT_OPEN_DRAIN (0b01)
#define GPIO_CNF_OUTPUT_ALT_PUSH_PULL (0b10)
#define GPIO_CNF_OUTPUT_ALT_OPEN_DRAIN (0b11)
#define GPIO_MODE_INPUT (0b00)
#define GPIO_MODE_OUTPUT_10MHZ (0b01)
#define GPIO_MODE_OUTPUT_2MHZ (0b10)
#define GPIO_MODE_OUTPUT_50MHZ (0b11)
/*
┌───────────────────────┐
│ Structure Definitions │
└───────────────────────┘
*/
// RCC Clock control register (RCC_CR 7.3.1)
typedef struct {
uint32_t hsi_on : 1;
uint32_t hsi_rdy : 1;
uint32_t reserved1 : 1;
uint32_t hsi_trim : 5;
uint32_t hsi_cal : 8;
uint32_t hse_on : 1;
uint32_t hse_rdy : 1;
uint32_t hse_byp : 1;
uint32_t css_on : 1;
uint32_t reserved2 : 4;
uint32_t pll_on : 1;
uint32_t pll_rdy : 1;
uint32_t reserved3 : 6;
} RCC_CR_t;
// Clock configuration register (RCC_CFGR 7.3.2)
typedef struct {
uint32_t sw : 2;
uint32_t sws : 2;
uint32_t h_pre : 4;
uint32_t p_pre1 : 3;
uint32_t p_pre2 : 3;
uint32_t adc_pre : 2;
uint32_t pll_src : 1;
uint32_t pll_xtrp_pre : 1;
uint32_t pll_mul : 4;
uint32_t usb_pre : 1;
uint32_t reserved1 : 1;
uint32_t mco : 3;
uint32_t reserved2 : 5;
} RCC_CFGR_t;
// clock enable register (RCC_APB2ENR 7.3.7)
typedef struct {
uint32_t afioen : 1;
uint32_t reserved1 : 1;
uint32_t iopaen : 1;
uint32_t iopben : 1;
uint32_t iopcen : 1;
uint32_t iopden : 1;
uint32_t iopeen : 1;
uint32_t iopfen : 1;
uint32_t iopgen : 1;
uint32_t adc1en : 1;
uint32_t adc2en : 1;
uint32_t tim1en : 1;
uint32_t spi1en : 1;
uint32_t tim8en : 1;
uint32_t usart1en : 1;
uint32_t adc3en : 1;
uint32_t reserved2 : 3;
uint32_t tim9en : 1;
uint32_t tim10en : 1;
uint32_t tim11en : 1;
uint32_t reserved3 : 10;
} RCC_APB2ENR_t;
// Flash access control register (FLASH_ACR 3.3.3)
typedef struct {
uint32_t latency : 3;
uint32_t hlfcya : 1;
uint32_t prftbe : 1;
uint32_t prftbs : 1;
uint32_t reserved : 24;
} FLASH_ACR_t;
// Port configuration register low (GPIOX_CRL 9.2.1)
typedef struct {
uint32_t mode0 : 2;
uint32_t cnf0 : 2;
uint32_t mode1 : 2;
uint32_t cnf1 : 2;
uint32_t mode2 : 2;
uint32_t cnf2 : 2;
uint32_t mode3 : 2;
uint32_t cnf3 : 2;
uint32_t mode4 : 2;
uint32_t cnf4 : 2;
uint32_t mode5 : 2;
uint32_t cnf5 : 2;
uint32_t mode6 : 2;
uint32_t cnf6 : 2;
uint32_t mode7 : 2;
uint32_t cnf7 : 2;
} GPIOX_CRL_t;
// Port configuration register high (GPIOX_CRH 9.2.2)
typedef struct {
uint32_t mode8 : 2;
uint32_t cnf8 : 2;
uint32_t mode9 : 2;
uint32_t cnf9 : 2;
uint32_t mode10 : 2;
uint32_t cnf10 : 2;
uint32_t mode11 : 2;
uint32_t cnf11 : 2;
uint32_t mode12 : 2;
uint32_t cnf12 : 2;
uint32_t mode13 : 2;
uint32_t cnf13 : 2;
uint32_t mode14 : 2;
uint32_t cnf14 : 2;
uint32_t mode15 : 2;
uint32_t cnf15 : 2;
} GPIOX_CRH_t;
// Port input data register (GPIOX_IDR 9.2.3)
typedef struct {
uint32_t idr0 : 1;
uint32_t idr1 : 1;
uint32_t idr2 : 1;
uint32_t idr3 : 1;
uint32_t idr4 : 1;
uint32_t idr5 : 1;
uint32_t idr6 : 1;
uint32_t idr7 : 1;
uint32_t idr8 : 1;
uint32_t idr9 : 1;
uint32_t idr10 : 1;
uint32_t idr11 : 1;
uint32_t idr12 : 1;
uint32_t idr13 : 1;
uint32_t idr14 : 1;
uint32_t idr15 : 1;
uint32_t reserved : 16;
} GPIOX_IDR_t;
// Port output data register (GPIOX_ODR 9.2.4)
typedef struct {
uint32_t odr0 : 1;
uint32_t odr1 : 1;
uint32_t odr2 : 1;
uint32_t odr3 : 1;
uint32_t odr4 : 1;
uint32_t odr5 : 1;
uint32_t odr6 : 1;
uint32_t odr7 : 1;
uint32_t odr8 : 1;
uint32_t odr9 : 1;
uint32_t odr10 : 1;
uint32_t odr11 : 1;
uint32_t odr12 : 1;
uint32_t odr13 : 1;
uint32_t odr14 : 1;
uint32_t odr15 : 1;
uint32_t reserved : 16;
} GPIOX_ODR_t;
// AFIO Event control register (AFIO_EVCR 9.4)
typedef struct {
uint32_t pin : 4;
uint32_t port : 3;
uint32_t evoe : 1;
uint32_t reserved : 24;
} AFIO_EVCR_t;
// AFIO External interrupt configuration register 1 (AFIO_EXTICR1 9.4.3)
typedef struct {
uint32_t exti0 : 4;
uint32_t exti1 : 4;
uint32_t exti2 : 4;
uint32_t exti3 : 4;
uint32_t reserved : 16;
} AFIO_EXTICR1_t;
// AFIO External interrupt configuration register 2 (AFIO_EXTICR2 9.4.4)
typedef struct {
uint32_t exti4 : 4;
uint32_t exti5 : 4;
uint32_t exti6 : 4;
uint32_t exti7 : 4;
uint32_t reserved : 16;
} AFIO_EXTICR2_t;
// AFIO External interrupt configuration register 3 (AFIO_EXTICR3 9.4.5)
typedef struct {
uint32_t exti8 : 4;
uint32_t exti9 : 4;
uint32_t exti10 : 4;
uint32_t exti11 : 4;
uint32_t reserved : 16;
} AFIO_EXTICR3_t;
// AFIO External interrupt configuration register 4 (AFIO_EXTICR4 9.4.6)
typedef struct {
uint32_t exti12 : 4;
uint32_t exti13 : 4;
uint32_t exti14 : 4;
uint32_t exti15 : 4;
uint32_t reserved : 16;
} AFIO_EXTICR4_t;
// EXTI mask register (EXTI_IMR 10.3.1 EXTI_EMR 10.3.2)
struct EXTI_MR_t {
uint32_t mr0 : 1;
uint32_t mr1 : 1;
uint32_t mr2 : 1;
uint32_t mr3 : 1;
uint32_t mr4 : 1;
uint32_t mr5 : 1;
uint32_t mr6 : 1;
uint32_t mr7 : 1;
uint32_t mr8 : 1;
uint32_t mr9 : 1;
uint32_t mr10 : 1;
uint32_t mr11 : 1;
uint32_t mr12 : 1;
uint32_t mr13 : 1;
uint32_t mr14 : 1;
uint32_t mr15 : 1;
uint32_t mr16 : 1;
uint32_t mr17 : 1;
uint32_t mr18 : 1;
uint32_t mr19 : 1;
uint32_t reserved : 12;
};
typedef struct EXTI_MR_t EXTI_IMR_t;
typedef struct EXTI_MR_t EXTI_EMR_t;
// EXTI trigger selection register (EXTI_RTSR 10.3.3 EXTI_FTSR 10.3.4)
struct EXTI_TSR_t {
uint32_t tr0 : 1;
uint32_t tr1 : 1;
uint32_t tr2 : 1;
uint32_t tr3 : 1;
uint32_t tr4 : 1;
uint32_t tr5 : 1;
uint32_t tr6 : 1;
uint32_t tr7 : 1;
uint32_t tr8 : 1;
uint32_t tr9 : 1;
uint32_t tr10 : 1;
uint32_t tr11 : 1;
uint32_t tr12 : 1;
uint32_t tr13 : 1;
uint32_t tr14 : 1;
uint32_t tr15 : 1;
uint32_t tr16 : 1;
uint32_t tr17 : 1;
uint32_t tr18 : 1;
uint32_t tr19 : 1;
uint32_t reserved : 12;
};
typedef struct EXTI_TSR_t EXTI_RTSR_t;
typedef struct EXTI_TSR_t EXTI_FTSR_t;
// EXTI software interrupt event register (EXTI_SWIER 10.3.5)
typedef struct {
uint32_t swier0 : 1;
uint32_t swier1 : 1;
uint32_t swier2 : 1;
uint32_t swier3 : 1;
uint32_t swier4 : 1;
uint32_t swier5 : 1;
uint32_t swier6 : 1;
uint32_t swier7 : 1;
uint32_t swier8 : 1;
uint32_t swier9 : 1;
uint32_t swier10 : 1;
uint32_t swier11 : 1;
uint32_t swier12 : 1;
uint32_t swier13 : 1;
uint32_t swier14 : 1;
uint32_t swier15 : 1;
uint32_t swier16 : 1;
uint32_t swier17 : 1;
uint32_t swier18 : 1;
uint32_t swier19 : 1;
uint32_t reserved : 12;
} EXTI_SWIER_t;
// EXTI pending register (EXTI_PR 10.3.6)
typedef struct {
uint32_t pr0 : 1;
uint32_t pr1 : 1;
uint32_t pr2 : 1;
uint32_t pr3 : 1;
uint32_t pr4 : 1;
uint32_t pr5 : 1;
uint32_t pr6 : 1;
uint32_t pr7 : 1;
uint32_t pr8 : 1;
uint32_t pr9 : 1;
uint32_t pr10 : 1;
uint32_t pr11 : 1;
uint32_t pr12 : 1;
uint32_t pr13 : 1;
uint32_t pr14 : 1;
uint32_t pr15 : 1;
uint32_t pr16 : 1;
uint32_t pr17 : 1;
uint32_t pr18 : 1;
uint32_t pr19 : 1;
uint32_t reserved : 12;
} EXTI_PR_t;
#endif // MAIN_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment