add generic way to get register addresses

This commit is contained in:
King Kévin 2016-08-18 10:45:36 +02:00
parent abb59970bd
commit 045f533afa
5 changed files with 233 additions and 128 deletions

114
global.c Normal file
View File

@ -0,0 +1,114 @@
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** global definitions and methods (code)
* @file global.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/timer.h> // timer library
#include <libopencm3/cm3/nvic.h> // interrupt handler
#include <libopencm3/stm32/exti.h> // external interrupt defines
#include "global.h" // common methods
volatile bool button_flag = false;
const uint32_t GPIO[] = {GPIOA,GPIOB,GPIOC,GPIOD,GPIOE,GPIOF,GPIOG};
const uint32_t RCC_GPIO[] = {RCC_GPIOA,RCC_GPIOB,RCC_GPIOC,RCC_GPIOD,RCC_GPIOE,RCC_GPIOF,RCC_GPIOG};
const uint32_t TIM[] = {~0,TIM1,TIM2,TIM3,TIM4,TIM5,TIM6,TIM7,TIM8,TIM9,TIM10,TIM11,TIM12,TIM13,TIM14,TIM15,TIM16,TIM17};
const uint32_t RCC_TIM[] = {~0,RCC_TIM1,RCC_TIM2,RCC_TIM3,RCC_TIM4,RCC_TIM5,RCC_TIM6,RCC_TIM7,RCC_TIM8,RCC_TIM9,RCC_TIM10,RCC_TIM11,RCC_TIM12,RCC_TIM13,RCC_TIM14,RCC_TIM15,RCC_TIM16,RCC_TIM17};
const uint32_t NVIC_TIM_IRQ[] = {~0,~0,NVIC_TIM2_IRQ,NVIC_TIM3_IRQ,NVIC_TIM4_IRQ,NVIC_TIM5_IRQ,NVIC_TIM6_IRQ,NVIC_TIM7_IRQ,~0,~0,~0,~0,~0,~0,~0,~0,~0,~0};
char* b2s(uint64_t binary, uint8_t rjust)
{
static char string[64+1] = {0}; // the string representation to return
int8_t bit = LENGTH(string)-1; // the index of the bit to print
string[bit--] = 0; // terminate string
while (binary) {
if (binary & 1) {
string[bit--] = '1';
} else {
string[bit--] = '0';
}
binary >>= 1;
}
while (64-bit-1<rjust && bit>=0) {
string[bit--] = '0';
}
return &string[bit+1];
}
/** switch on board LED */
void led_on(void)
{
#if defined(SYSTEM_BOARD) || defined(BLUE_PILL)
gpio_clear(LED_PORT, LED_PIN);
#elif defined(MAPLE_MINI)
gpio_set(LED_PORT, LED_PIN);
#endif
}
/** switch off board LED */
void led_off(void)
{
#if defined(SYSTEM_BOARD) || defined(BLUE_PILL)
gpio_set(LED_PORT, LED_PIN);
#elif defined(MAPLE_MINI)
gpio_clear(LED_PORT, LED_PIN);
#endif
}
/** toggle board LED */
void led_toggle(void)
{
gpio_toggle(LED_PORT, LED_PIN);
}
void board_setup(void)
{
// setup LED
rcc_periph_clock_enable(LED_RCC); // enable clock for LED
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); // set LED pin to 'output push-pull'
led_off(); // switch off LED per default
// setup button
#if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ)
rcc_periph_clock_enable(BUTTON_RCC); // enable clock for button
gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, BUTTON_PIN); // set button pin to input
gpio_clear(BUTTON_PORT, BUTTON_PIN); // pull down to be able to detect button push (go high)
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
exti_select_source(BUTTON_EXTI, BUTTON_PORT); // mask external interrupt of this pin only for this port
exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_RISING); // trigger when button is pressed
exti_enable_request(BUTTON_EXTI); // enable external interrupt
nvic_enable_irq(BUTTON_IRQ); // enable interrupt
#endif
}
#if defined(BUTTON_ISR) && defined(BUTTON_EXTI)
/** interrupt service routine called when button is pressed */
void BUTTON_ISR(void)
{
exti_reset_request(BUTTON_EXTI); // reset interrupt
button_flag = true; // perform button action
}
#endif

100
global.h
View File

@ -12,54 +12,44 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** global definitions and methods
/** global definitions and methods (API)
* @file global.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
*/
#pragma once
#include <libopencm3/stm32/gpio.h> // GPIO defines
#include <libopencm3/cm3/nvic.h> // interrupt defines
#include <libopencm3/stm32/exti.h> // external interrupt defines
/** get the length of an array */
#define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
/** concatenate 2 arguments (used to defer concatenation) */
#define CAT2(x,y) x##y
/** concatenate 3 arguments (used to defer concatenation) */
#define CAT3(x,y,z) x##y##z
/** @defgroup reg_macro macros to get define values based on other defines values
/** @defgroup reg_table get register address based on identifier
* @note used when the value is not calculated
* @{
*/
/** get RCC for GPIO based on GPIO */
#define RCC_GPIO(x) switch (x) { \
case GPIOA: RCC_GPIOA; break; \
case GPIOB: RCC_GPIOB; break; \
case GPIOC: RCC_GPIOC; break; \
case GPIOD: RCC_GPIOD; break; \
case GPIOE: RCC_GPIOE; break; \
case GPIOF: RCC_GPIOF; break; \
case GPIOG: RCC_GPIOG; break; \
default: 0; break; \
}
/** get GPIO port based on port identifier (0=A, ...) */
extern const uint32_t GPIO[];
/** get RCC for GPIO based on GPIO identifier */
extern const uint32_t RCC_GPIO[];
/** get TIM based on TIM identifier */
extern const uint32_t TIM[];
/** get RCC for timer based on TIM */
#define RCC_TIM(x) switch (x) { \
case TIM1: RCC_TIM1; break; \
case TIM2: RCC_TIM2; break; \
case TIM3: RCC_TIM3; break; \
case TIM4: RCC_TIM4; break; \
case TIM5: RCC_TIM5; break; \
case TIM6: RCC_TIM6; break; \
case TIM7: RCC_TIM7; break; \
case TIM8: RCC_TIM8; break; \
case TIM9: RCC_TIM9; break; \
case TIM10: RCC_TIM10; break; \
case TIM11: RCC_TIM11; break; \
case TIM12: RCC_TIM12; break; \
case TIM13: RCC_TIM13; break; \
case TIM14: RCC_TIM14; break; \
case TIM15: RCC_TIM15; break; \
case TIM16: RCC_TIM16; break; \
case TIM17: RCC_TIM17; break; \
default: 0; break; \
}
extern const uint32_t RCC_TIM[];
/** get NVIC IRQ for timer base on TIM */
extern const uint32_t NVIC_TIM_IRQ[];
/** @} */
/** @defgroup reg_macro macros to get define values based on other defines values
* @note used when the value is calculated or isn't a value
* @{
*/
/** get GPIO pin based on pin identifier */
#define GPIO(x) (1<<x)
/** get interrupt service routine for timer base on TIM */
#define TIM_ISR(x) CAT3(TIM,x,_IRQHandler)
/** @} */
/** @defgroup board_led board LED GPIO
@ -97,31 +87,11 @@
#endif
/** @} */
/** switch on board LED */
inline void led_on(void)
{
#if defined(SYSTEM_BOARD) || defined(BLUE_PILL)
gpio_clear(LED_PORT, LED_PIN);
#elif defined(MAPLE_MINI)
gpio_set(LED_PORT, LED_PIN);
#endif
}
/** switch off board LED */
inline void led_off(void)
{
#if defined(SYSTEM_BOARD) || defined(BLUE_PILL)
gpio_set(LED_PORT, LED_PIN);
#elif defined(MAPLE_MINI)
gpio_clear(LED_PORT, LED_PIN);
#endif
}
/** toggle board LED */
inline void led_toggle(void)
{
gpio_toggle(LED_PORT, LED_PIN);
}
extern volatile bool button_flag; /**< flag set when board user button has been pressed/released */
/** default printf output */
int _write(int file, char *ptr, int len);
/** get binary representation of a number
* @param[in] binary number to represent in binary
* @param[in] rjust justify representation with leading zeros
@ -129,3 +99,15 @@ int _write(int file, char *ptr, int len);
*/
char* b2s(uint64_t binary, uint8_t rjust);
/** switch on board LED */
void led_on(void);
/** switch off board LED */
void led_off(void);
/** toggle board LED */
void led_toggle(void);
/** setup board peripherals */
void board_setup(void);

View File

@ -28,6 +28,7 @@
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/timer.h> // timer library
#include <libopencm3/cm3/nvic.h> // interrupt handler
#include <libopencmsis/stm32/f1/irqhandlers.h> // interrupt handler
#include "usart_soft.h" // software USART library API
#include "global.h" // common methods
@ -35,29 +36,76 @@
/** @defgroup usart_soft_gpio GPIO used for the software USART ports
* @{
*/
const static uint32_t usart_soft_rx_ports[USART_SOFT_PORTS] = {}; /**< GPIO ports for RX signals */
const static uint32_t usart_soft_rx_pins[USART_SOFT_PORTS] = {}; /**< GPIO pins for RX signals */
static const uint32_t usart_soft_rx_ports[USART_SOFT_RX_PORTS] = {0}; /**< GPIO ports for receive signals */
static const uint32_t usart_soft_rx_pins[USART_SOFT_RX_PORTS] = {0}; /**< GPIO pins for receive signals */
static const uint32_t usart_soft_tx_ports[USART_SOFT_TX_PORTS] = {0}; /**< GPIO ports for transmit signals */
static const uint32_t usart_soft_tx_pins[USART_SOFT_TX_PORTS] = {0}; /**< GPIO pins for transmit signals */
/** @} */
/** @defgroup usart_soft_config USART configurations
* @note this implementation is designed for 8N1 configuration since this is the most common case
* @note this implementation is designed for 8 bits, no parity, any stop configuration since this is the most common case
* @{
*/
const static uint32_t usart_soft_baudrate[USART_SOFT_PORTS] = {}; /**< baudrate for USART communication */
static const uint32_t usart_soft_rx_baudrates[USART_SOFT_RX_PORTS] = {9600}; /**< receive signal baudrates (2400-115200) */
static const uint32_t usart_soft_tx_baudrates[USART_SOFT_TX_PORTS] = {0}; /**< transmit signal baudrates (2400-115200) */
/** @} */
/** @defgroup usart_soft_timer timer used to same USART signals
* @{
*/
#define USART_SOFT_RX_TIMER 3 /**< timer peripheral for receive signals */
#define USART_SOFT_TX_TIMER 4 /**< timer peripheral for transmit signals */
/** @} */
void usart_soft_setup(void)
bool usart_soft_setup(void)
{
// setup GPIOs
for (uint8_t i = 0; i < USART_SOFT_PORTS; i++) {
rcc_periph_clock_enable(RCC_GPIO(usart_soft_rx_ports[i])); // enable clock for GPIO peripheral
gpio_set_mode(usart_soft_rx_ports[i], GPIO_MODE_INPUT, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, LED_WS2812B_CLK_PIN); // set pin as output
gpio_set_mode(usart_soft_rx_ports[i], GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, usart_soft_rx_pins[i]); // setup GPIO pin USART receive
gpio_set(usart_soft_rx_ports[i], usart_soft_rx_pins[i]); // pull up to avoid noise when not connected
// verify configuration
if ((USART_SOFT_RX_PORTS<0) || (USART_SOFT_RX_PORTS>4)) {
return false;
}
if ((USART_SOFT_TX_PORTS<0) || (USART_SOFT_TX_PORTS>4)) {
return false;
}
for (uint8_t i = 0; i < USART_SOFT_RX_PORTS; i++) {
if ((usart_soft_rx_baudrates[i]<2400) || (usart_soft_rx_baudrates[i]>115200)) {
return false;
}
}
for (uint8_t i = 0; i < USART_SOFT_TX_PORTS; i++) {
if ((usart_soft_tx_baudrates[i]<2400) || (usart_soft_tx_baudrates[i]>115200)) {
return false;
}
}
// setup GPIOs
for (uint8_t i = 0; i < USART_SOFT_RX_PORTS; i++) {
rcc_periph_clock_enable(RCC_GPIO[usart_soft_rx_ports[i]]); // enable clock for GPIO peripheral
gpio_set_mode(GPIO[usart_soft_rx_ports[i]], GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO(usart_soft_rx_pins[i])); // setup GPIO pin USART receive
gpio_set(GPIO[usart_soft_rx_ports[i]], GPIO(usart_soft_rx_pins[i])); // pull up to avoid noise when not connected
}
for (uint8_t i = 0; i < USART_SOFT_TX_PORTS; i++) {
rcc_periph_clock_enable(RCC_GPIO[usart_soft_tx_ports[i]]); // enable clock for GPIO peripheral
gpio_set_mode(GPIO[usart_soft_tx_ports[i]], GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(usart_soft_tx_pins[i])); // setup GPIO pin USART transmit
}
// setup timer
if (USART_SOFT_RX_PORTS>0) {
rcc_periph_clock_enable(RCC_TIM[USART_SOFT_RX_TIMER]); // enable clock for timer peripheral
timer_reset(TIM[USART_SOFT_RX_TIMER]); // reset timer state
timer_set_mode(TIM[USART_SOFT_RX_TIMER], TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM[USART_SOFT_RX_TIMER], 0); // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq(NVIC_TIM_IRQ[USART_SOFT_RX_TIMER]); // allow interrupt for timer
}
if (USART_SOFT_TX_PORTS>0) {
rcc_periph_clock_enable(RCC_TIM[USART_SOFT_TX_TIMER]); // enable clock for timer peripheral
timer_reset(TIM[USART_SOFT_TX_TIMER]); // reset timer state
timer_set_mode(TIM[USART_SOFT_TX_TIMER], TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM[USART_SOFT_TX_TIMER], 0); // prescaler to be able to sample 2400-115200 bps (72MHz/2^16=1099<2400bps)
nvic_enable_irq(NVIC_TIM_IRQ[USART_SOFT_TX_TIMER]); // allow interrupt for timer
}
return true; // setup completed
}
void TIM_ISR(USART_SOFT_RX_TIMER)(void)
{
}

View File

@ -19,11 +19,16 @@
* @note peripherals used: GPIO @ref usart_soft_gpio, timer @ref usart_soft_timer
*/
/** number of software USART ports
/** number of software USART receive ports (0-4)
* @note the corresponding GPIOs need to be configured in @p usart_soft_gpio
*/
#define USART_SOFT_PORTS 1
/** setup software USART ports */
void usart_soft_setup(void);
#define USART_SOFT_RX_PORTS 1
/** number of software USART transmit ports (0-4)
* @note the corresponding GPIOs need to be configured in @p usart_soft_gpio
*/
#define USART_SOFT_TX_PORTS 1
/** setup software USART ports
* @return is setup succeeded, else the configuration is wrong
*/
bool usart_soft_setup(void);

62
main.c
View File

@ -23,9 +23,9 @@
#include <stdio.h> // standard I/O facilities
#include <stdlib.h> // standard utilities
#include <unistd.h> // standard streams
#include <errno.h> // error number utilities
#include <string.h> // string utilities
#include <math.h> // mathematical utilities
#include <errno.h> // error number utilities
/* STM32 (including CM3) libraries */
#include <libopencm3/stm32/rcc.h> // real-time control clock library
@ -40,19 +40,14 @@
#include "global.h" // board definitions
#include "usart.h" // USART utilities
#include "usb_cdcacm.h" // USB CDC ACM utilities
#include "usart_soft.h" // software USART utilities
/** @defgroup main_flags flag set in interrupts to be processed in main task
* @{
*/
volatile bool button_flag = false; /**< flag set when board user button has been pressed/released */
volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */
/** @} */
/** user input command */
char command[32] = {0};
/** user input command index */
uint8_t command_i = 0;
int _write(int file, char *ptr, int len)
{
int i; // how much data has been sent
@ -83,27 +78,10 @@ int _write(int file, char *ptr, int len)
return -1;
}
char* b2s(uint64_t binary, uint8_t rjust)
{
static char string[64+1] = {0}; // the string representation to return
int8_t bit = LENGTH(string)-1; // the index of the bit to print
string[bit--] = 0; // terminate string
while (binary) {
if (binary & 1) {
string[bit--] = '1';
} else {
string[bit--] = '0';
}
binary >>= 1;
}
while (64-bit-1<rjust && bit>=0) {
string[bit--] = '0';
}
return &string[bit+1];
}
/** user input command */
char command[32] = {0};
/** user input command index */
uint8_t command_i = 0;
/** process user command
* @param[in] str user command string (\0 ended)
@ -162,12 +140,10 @@ error:
int main(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz(); // use 8 MHz high speed external clock to generate 72 MHz internal clock
// setup LED
rcc_periph_clock_enable(LED_RCC); // enable clock for LED
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN); // set LED pin to 'output push-pull'
led_off(); // switch off LED per default
// setup board
board_setup();
// setup USART and USB for user communication
usart_setup(); // setup USART (for printing)
cdcacm_setup(); // setup USB CDC ACM (for printing)
@ -177,18 +153,6 @@ int main(void)
// minimal setup ready
printf("welcome to the STM32F1 CuVoodoo example code\n"); // print welcome message
// setup button
#if defined(BUTTON_RCC) && defined(BUTTON_PORT) && defined(BUTTON_PIN) && defined(BUTTON_EXTI) && defined(BUTTON_IRQ)
rcc_periph_clock_enable(BUTTON_RCC); // enable clock for button
gpio_set_mode(BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, BUTTON_PIN); // set button pin to input
gpio_clear(BUTTON_PORT, BUTTON_PIN); // pull down to be able to detect button push (go high)
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
exti_select_source(BUTTON_EXTI, BUTTON_PORT); // mask external interrupt of this pin only for this port
exti_set_trigger(BUTTON_EXTI, EXTI_TRIGGER_RISING); // trigger when button is pressed
exti_enable_request(BUTTON_EXTI); // enable external interrupt
nvic_enable_irq(BUTTON_IRQ); // enable interrupt
#endif
// setup RTC
printf("setup internal RTC: ");
rtc_auto_awake(RCC_LSE, 32768-1); // ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect)
@ -264,14 +228,6 @@ int main(void)
return 0;
}
#if defined(BUTTON_ISR) && defined(BUTTON_EXTI)
/** interrupt service routine called when button is pressed */
void BUTTON_ISR(void)
{
exti_reset_request(BUTTON_EXTI); // reset interrupt
button_flag = true; // perform button action
}
#endif
/** @brief interrupt service routine called when tick passed on RTC */
void rtc_isr(void)