fan_monitor/src/drivers/io.c
2020-02-25 19:54:23 -05:00

233 lines
5.3 KiB
C

//target header
#include "../target/stm32f103xb.h"
//custom header
#include "../config.h"
//std headers
#include <stdlib.h>
//driver header
#include "io.h"
static OnIO io_cb[16]={
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
void EXTI0_IRQHandler() {
if (io_cb[0]) (io_cb[0])();
EXTI->PR = 1<<0;
}
void EXTI1_IRQHandler() {
if (io_cb[1]) (io_cb[1])();
EXTI->PR = 1<<1;
}
void EXTI2_IRQHandler() {
if (io_cb[2]) (io_cb[2])();
EXTI->PR = 1<<2;
}
void EXTI3_IRQHandler() {
if (io_cb[3]) (io_cb[3])();
EXTI->PR = 1<<3;
}
void EXTI4_IRQHandler() {
if (io_cb[4]) (io_cb[4])();
EXTI->PR = 1<<4;
}
void EXTI9_5_IRQHandler() {
if (EXTI->PR & (1<<5)) {
if (io_cb[5]) (io_cb[5])();
EXTI->PR = 1<<5;
} else if (EXTI->PR & (1<<6)) {
if (io_cb[6]) (io_cb[6])();
EXTI->PR = 1<<6;
} else if (EXTI->PR & (1<<7)) {
if (io_cb[7]) (io_cb[7])();
EXTI->PR = 1<<7;
} else if (EXTI->PR & (1<<8)) {
if (io_cb[8]) (io_cb[8])();
EXTI->PR = 1<<8;
} else if (EXTI->PR & (1<<9)) {
if (io_cb[9]) (io_cb[9])();
EXTI->PR = 1<<9;
}
}
void EXTI15_10_IRQHandler() {
if (EXTI->PR & (1<<10)) {
if (io_cb[10]) (io_cb[10])();
EXTI->PR = 1<<10;
} else if (EXTI->PR & (1<<11)) {
if (io_cb[11]) (io_cb[11])();
EXTI->PR = 1<<11;
} else if (EXTI->PR & (1<<12)) {
if (io_cb[12]) (io_cb[12])();
EXTI->PR = 1<<12;
} else if (EXTI->PR & (1<<13)) {
if (io_cb[13]) (io_cb[13])();
EXTI->PR = 1<<13;
} else if (EXTI->PR & (1<<14)) {
if (io_cb[14]) (io_cb[14])();
EXTI->PR = 1<<14;
} else if (EXTI->PR & (1<<15)) {
if (io_cb[15]) (io_cb[15])();
EXTI->PR = 1<<15;
}
}
/* Definitions for EXTI configuration */
enum io_exti_mask {
SYSCFG_EXTI_PA_MASK = 0x0,
SYSCFG_EXTI_PB_MASK = 0x1,
SYSCFG_EXTI_PC_MASK = 0x2,
SYSCFG_EXTI_PD_MASK = 0x3,
SYSCFG_EXTI_PE_MASK = 0x4
};
int io_configure(GPIO_TypeDef *gpio, uint16_t pin, uint16_t pin_cfg, OnIO cb) {
// enable GPIOx subsystem clocking
if (gpio == GPIOA) RCC->APB2ENR |= 1<<2;
else if (gpio == GPIOB) RCC->APB2ENR |= 1<<3;
else if (gpio == GPIOC) RCC->APB2ENR |= 1<<4;
else if (gpio == GPIOD) RCC->APB2ENR |= 1<<5;
else if (gpio == GPIOE) RCC->APB2ENR |= 1<<6;
// setup pin mask for crx registers
uint64_t pin_mask = 0;
for(int i=0; i<16; ++i) {
if((pin >> i) & 0x1) pin_mask |= 0x1ll << 4*i;
}
// clear previous data
uint64_t crx = pin_mask * 0x4; //reset value is 0x4
uint16_t odr = pin;
gpio->CRH &= ~(crx >> 32);
gpio->CRL &= ~(crx & 0xFFFFFFFF);
gpio->BSRR |= odr << 16;
// set up the new configuration
crx = pin_mask * (pin_cfg & 0xF);
odr = pin * ((pin_cfg & 0x10) >> 4);
gpio->CRH |= crx >> 32;
gpio->CRL |= crx & 0xFFFFFFFF;
gpio->BSRR |= odr;
//TODO manage alternate functions
// manage IRQs //TODO allow IRQ reset
if (!cb) return 0; //no callback attached
if (pin_cfg & 0x7) return -1; //callback set, but not in input mode
RCC->APB2ENR |= 0x1; //enable AFIO clocking
// prepare mask
uint8_t port_mask = 0;
// uint32_t pin_mask = 0;
if (gpio == GPIOA) port_mask = SYSCFG_EXTI_PA_MASK;
else if (gpio == GPIOB) port_mask = SYSCFG_EXTI_PB_MASK;
else if (gpio == GPIOC) port_mask = SYSCFG_EXTI_PC_MASK;
else if (gpio == GPIOD) port_mask = SYSCFG_EXTI_PD_MASK;
else if (gpio == GPIOE) port_mask = SYSCFG_EXTI_PE_MASK;
// setup external IRQ lines
uint64_t afio_mask;
for(int i=0; i<4; ++i) {
afio_mask = ((pin_mask & (0xFFFFll << (i*16))) >> (i*16)) * port_mask;
if(afio_mask) AFIO->EXTICR[i] |= afio_mask;
}
// clear pending IRQs on concerned lines
EXTI->PR |= pin;
// configure IRQ options and masks
EXTI->IMR |= pin;
if(pin_cfg & 0x100) EXTI->RTSR |= pin;
if(pin_cfg & 0x200) EXTI->FTSR |= pin; //in case both falling and rising
//are set, both will be a trigger
// register IRQ callbacks
for(int i=0; i<16; ++i) {
if((pin >> i) & 0x1) {
io_cb[i] = cb;
// Setup NVIC
switch (i) {
case 0:
NVIC_SetPriority(EXTI0_IRQn, EXTI0_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI0_IRQn);
break;
case 1:
NVIC_SetPriority(EXTI1_IRQn, EXTI1_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI1_IRQn);
break;
case 2:
NVIC_SetPriority(EXTI2_IRQn, EXTI2_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI2_IRQn);
break;
case 3:
NVIC_SetPriority(EXTI3_IRQn, EXTI3_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI3_IRQn);
break;
case 4:
NVIC_SetPriority(EXTI4_IRQn, EXTI4_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI4_IRQn);
break;
case 5:
case 6:
case 7:
case 8:
case 9:
NVIC_SetPriority(EXTI9_5_IRQn, EXTI9_5_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI9_5_IRQn);
break;
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
NVIC_SetPriority(EXTI15_10_IRQn, EXTI15_10_IRQ_PRIORITY);
NVIC_EnableIRQ(EXTI15_10_IRQn);
break;
default:
return -1; //impossible to get there
}
}
}
return 0;
}
uint32_t io_read(GPIO_TypeDef *gpio, uint16_t mask)
{
return gpio->IDR & mask;
}
void io_write(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask)
{
gpio->BSRR = (uint32_t)(mask) << (val ? 0 : 16);
}
void io_write_n(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask)
{
gpio->BSRR = (uint32_t)(mask) << (val ? 16 : 0);
}
void io_set(GPIO_TypeDef *gpio, uint16_t mask)
{
gpio->BSRR = mask;
}
void io_clear(GPIO_TypeDef *gpio, uint16_t mask)
{
gpio->BSRR = (uint32_t)(mask) << 16;
}