add doxygen documentation

This commit is contained in:
King Kévin 2016-03-24 10:37:42 +01:00
parent d6f3efb001
commit 3a0d9e6186
14 changed files with 2543 additions and 171 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@
*.elf *.elf
*.bin *.bin
*.swp *.swp
doc

2303
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@ BOARD = SYSTEM_BOARD
# source files # source files
CSRC = $(wildcard *.c) CSRC = $(wildcard *.c)
CHDR = $(wildcard *.h)
OBJ = $(patsubst %.c,%.o,$(CSRC)) OBJ = $(patsubst %.c,%.o,$(CSRC))
# figure out based on the includes which library files are used in the main CSRC files # figure out based on the includes which library files are used in the main CSRC files
DEPENDENCIES = $(patsubst %.c,%.inc,$(CSRC)) DEPENDENCIES = $(patsubst %.c,%.inc,$(CSRC))
@ -39,6 +40,7 @@ LIB = lib
# the library files to use # the library files to use
# this will be populated using includes based DEPENDENCIES # this will be populated using includes based DEPENDENCIES
LIB_CSRC = LIB_CSRC =
LIB_CHDR = $(patsubst %.c,%.h,$(LIB_CSRC))
LIB_OBJ = $(patsubst %.c,%.o,$(LIB_CSRC)) LIB_OBJ = $(patsubst %.c,%.o,$(LIB_CSRC))
# populates LIB_CSRC based on the library files used # populates LIB_CSRC based on the library files used
-include $(DEPENDENCIES) -include $(DEPENDENCIES)
@ -164,6 +166,10 @@ list: $(BINARY).list
%.inc: %.d %.inc: %.d
$(Q)grep -o -e " ${LIB}\/[^ ]*\.h" $(<) | sed -e 's/\.h$$/.c/g' -e 's/^/LIB_CSRC +=/' > $(@) $(Q)grep -o -e " ${LIB}\/[^ ]*\.h" $(<) | sed -e 's/\.h$$/.c/g' -e 's/^/LIB_CSRC +=/' > $(@)
# doxygen documentation
doc: Doxyfile $(CSRC) $(CHDR) $(LIB_CSRC) $(LIB_CHDR)
$(Q)doxygen $(<)
clean: clean:
$(Q)$(RM) $(BINARY).elf $(BINARY).bin $(BINARY).hex $(BINARY).map $(OBJ) $(LIB_OBJ) $(LIB)/*.o $(DEPENDENCIES) $(Q)$(RM) $(BINARY).elf $(BINARY).bin $(BINARY).hex $(BINARY).map $(OBJ) $(LIB_OBJ) $(LIB)/*.o $(DEPENDENCIES)

View File

@ -104,4 +104,7 @@ this allows to restart the bootloader and flash new firmware using DFU.
to reset the board run `make reset`. to reset the board run `make reset`.
this only works if the USB CDC ACM run correctly and the micro-controller isn't stuck. this only works if the USB CDC ACM run correctly and the micro-controller isn't stuck.
documentation
=============
to generate doxygen documentation run `make doc`.

View File

@ -12,36 +12,40 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief global definitions and methods
* @file global.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
*/
#pragma once #pragma once
#include <libopencm3/stm32/gpio.h> // GPIO defines #include <libopencm3/stm32/gpio.h> // GPIO defines
#include <libopencm3/cm3/nvic.h> // interrupt defines #include <libopencm3/cm3/nvic.h> // interrupt defines
#include <libopencm3/stm32/exti.h> // external interrupt defines #include <libopencm3/stm32/exti.h> // external interrupt defines
/* get the length of an array */ /** get the length of an array */
#define LENGTH(x) (sizeof(x) / sizeof((x)[0])) #define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
/* LED pin */ /* board LED GPIO */
#if defined(SYSTEM_BOARD) #if defined(SYSTEM_BOARD)
/* on system board LED is on pin 11/PA1 */ /** on system board LED is on pin 11/PA1 */
#define LED_RCC RCC_GPIOA #define LED_RCC RCC_GPIOA
#define LED_PORT GPIOA #define LED_PORT GPIOA
#define LED_PIN GPIO1 #define LED_PIN GPIO1
#elif defined(BLUE_PILL) #elif defined(BLUE_PILL)
/* on minimum system LED is on pin 2/PC13 */ /** on minimum system LED is on pin 2/PC13 */
#define LED_RCC RCC_GPIOC #define LED_RCC RCC_GPIOC
#define LED_PORT GPIOC #define LED_PORT GPIOC
#define LED_PIN GPIO13 #define LED_PIN GPIO13
#elif defined (MAPLE_MINI) #elif defined (MAPLE_MINI)
/* on maple mini LED is on pin 19/PB1 */ /** on maple mini LED is on pin 19/PB1 */
#define LED_RCC RCC_GPIOB #define LED_RCC RCC_GPIOB
#define LED_PORT GPIOB #define LED_PORT GPIOB
#define LED_PIN GPIO1 #define LED_PIN GPIO1
#endif #endif
/* user button */ /* board user button GPIO */
#if defined(MAPLE_MINI) #if defined(MAPLE_MINI)
/* on maple mini button is on 32/PB8 */ /** on maple mini user button is on 32/PB8 */
#define BUTTON_RCC RCC_GPIOB #define BUTTON_RCC RCC_GPIOB
#define BUTTON_PORT GPIOB #define BUTTON_PORT GPIOB
#define BUTTON_PIN GPIO8 #define BUTTON_PIN GPIO8
@ -50,14 +54,18 @@
#define BUTTON_ISR exti9_5_isr #define BUTTON_ISR exti9_5_isr
#endif #endif
/* switch on LED */ /** @brief switch on board LED */
void led_on(void); void led_on(void);
/* switch off LED */ /** @brief switch off board LED */
void led_off(void); void led_off(void);
/* toggle LED */ /** @brief toggle board LED */
void led_toggle(void); void led_toggle(void);
/* default output (i.e. for printf) */ /** @brief default printf output */
int _write(int file, char *ptr, int len); int _write(int file, char *ptr, int len);
/* print binary as string */ /** @brief get binary representation of a number
* @param[in] binary number to represent in binary
* @param[in] rjust justify representation with leading zeros
* @return string with binary representation of the number
*/
char* b2s(uint32_t binary, uint8_t rjust); char* b2s(uint32_t binary, uint8_t rjust);

View File

@ -12,9 +12,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief library to drive a WS2812b LED chain (code)
/* this library is used to drive a WS2812b LED chain */ * @file led_ws2812b.c
/* peripherals used: SPI , timer, DMA (check source for details) */ * @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
* @note peripherals used: SPI @ref led_ws2812b_spi, timer @ref led_ws2812b_timer, DMA @ref led_ws2812b_dma
*/
/* standard libraries */ /* standard libraries */
#include <stdint.h> // standard integer types #include <stdint.h> // standard integer types
@ -32,38 +35,50 @@
#include "led_ws2812b.h" // LED WS2812b library API #include "led_ws2812b.h" // LED WS2812b library API
#include "global.h" // global definitions #include "global.h" // global definitions
/* WS2812b peripheral configuration */ /** peripheral configuration */
#define WS2812B_SPI SPI1 /** @defgroup led_ws2812b_spi SPI peripheral used to control the WS2812b LEDs
#define WS2812B_SPI_DR SPI1_DR * @{
#define WS2812B_SPI_RCC RCC_SPI1 */
#define WS2812B_SPI_PORT GPIOA #define WS2812B_SPI SPI1 /**< SPI peripheral */
#define WS2812B_SPI_CLK GPIO_SPI1_SCK // connect PWM output to clock input on PA5 #define WS2812B_SPI_DR SPI1_DR /**< SPI data register for the DMA */
#define WS2812B_SPI_DOUT GPIO_SPI1_MISO // connect WS2812b DIN to MISO pin PA6 #define WS2812B_SPI_RCC RCC_SPI1 /**< SPI peripheral clock */
#define WS2812B_TIMER TIM3 #define WS2812B_SPI_PORT GPIOA /**< SPI port */
#define WS2812B_TIMER_RCC RCC_TIM3 #define WS2812B_SPI_CLK GPIO_SPI1_SCK /**< SPI clock pin (PA5), connect to PWM output */
#define WS2812B_TIMER_OC TIM_OC3 #define WS2812B_SPI_DOUT GPIO_SPI1_MISO /**< SPI data pin (PA6), connect to WS2812b DIN */
#define WS2812B_CLK_RCC RCC_GPIOB /** @} */
#define WS2812B_CLK_PORT GPIOB /** @defgroup led_ws2812b_timer timer peripheral used to generate SPI clock
#define WS2812B_CLK_PIN GPIO_TIM3_CH3 // connect SPI clock input to PWM clock output PB0 * @{
#define WS2812B_DMA DMA1 // DMA1 supports SPI1_TX interrupt */
#define WS2812B_DMA_RCC RCC_DMA1 // follows previous definition #define WS2812B_TIMER TIM3 /**< timer peripheral */
#define WS2812B_DMA_CH DMA_CHANNEL3 // only DMA1 channel 3 supports SPI1_TX interrupt #define WS2812B_TIMER_RCC RCC_TIM3 /**< timer peripheral clock */
#define WS2812B_DMA_IRQ NVIC_DMA1_CHANNEL3_IRQ // follows previous definition #define WS2812B_TIMER_OC TIM_OC3 /**< timer output compare used to set PWM frequency */
#define WS2812B_DMA_ISR dma1_channel3_isr // follows previous definition #define WS2812B_CLK_RCC RCC_GPIOB /**< timer port peripheral clock */
#define WS2812B_CLK_PORT GPIOB /**< timer port */
#define WS2812B_CLK_PIN GPIO_TIM3_CH3 /**< timer pin to output PWM (PB0), connect to SPI clock input */
/** @} */
/** @defgroup led_ws2812b_dma DMA peripheral used to send the data
* @{
*/
#define WS2812B_DMA DMA1 /**< DMA peripheral to put data for WS2812b LED in SPI queue (only DMA1 supports SPI1_TX interrupt) */
#define WS2812B_DMA_RCC RCC_DMA1 /**< DMA peripheral clock */
#define WS2812B_DMA_CH DMA_CHANNEL3 /**< DMA channel (only DMA1 channel 3 supports SPI1_TX interrupt) */
#define WS2812B_DMA_IRQ NVIC_DMA1_CHANNEL3_IRQ /**< DMA channel interrupt signal */
#define WS2812B_DMA_ISR dma1_channel3_isr /**< DMA channel interrupt service routine */
/** @} */
/* template to encode one byte /** @brief bit template to encode one byte to be shifted out by SPI to the WS2812b LEDs
* for each WS2812b bit which needs to be transfered we require to transfer 3 SPI bits * @details For each WS2812b bit which needs to be transfered we require to transfer 3 SPI bits.
* the first SPI bit is the high start of the WS2812b bit frame * The first SPI bit is the high start of the WS2812b bit frame.
* the second SPI bit determines if the WS2812b bit is a 0 or 1 * The second SPI bit determines if the WS2812b bit is a 0 or 1.
* the third SPI bit is the last part of the WS2812b bit frame, which is always low * The third SPI bit is the last part of the WS2812b bit frame, which is always low.
* only the first 24 bits (3*8) are used */ * Only the first 24 bits (3*8) are used.
#define WS2812B_SPI_TEMPLATE 0x92492400 //0b10010010010010010010010000000000 * The binary pattern is 0b10010010010010010010010000000000
*/
#define WS2812B_SPI_TEMPLATE 0x92492400
uint8_t ws2812b_data[WS2812B_LEDS*3*3+40*3/8] = {0}; // SPI encode data to be shifted out for WS2812b + the 50us reset uint8_t ws2812b_data[WS2812B_LEDS*3*3+40*3/8] = {0}; /**< data encoded to be shifted out by SPI for the WS2812b, pulse the 50us reset */
static volatile bool transmit_flag = false; // is transmission ongoing static volatile bool transmit_flag = false; // is transmission ongoing
/* set color of a single LED
* transmission needs to be done separately */
void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue) void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
{ {
// verify the led exists // verify the led exists
@ -90,7 +105,6 @@ void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue)
} }
} }
/* transmit colors to LEDs */
void ws2812b_transmit(void) void ws2812b_transmit(void)
{ {
while (transmit_flag) { // wait for previous transmission to complete while (transmit_flag) { // wait for previous transmission to complete
@ -108,7 +122,6 @@ void ws2812b_transmit(void)
timer_enable_counter(WS2812B_TIMER); // start timer to generate clock timer_enable_counter(WS2812B_TIMER); // start timer to generate clock
} }
/* setup WS2812b LED controller */
void ws2812b_setup(void) void ws2812b_setup(void)
{ {
/* setup timer to generate clock of (using PWM): 800kHz*3 */ /* setup timer to generate clock of (using PWM): 800kHz*3 */
@ -160,7 +173,7 @@ void ws2812b_setup(void)
ws2812b_transmit(); // set LEDs ws2812b_transmit(); // set LEDs
} }
/* data transmission finished */ /** @brief DMA interrupt service routine to stop transmission after it finished */
void WS2812B_DMA_ISR(void) void WS2812B_DMA_ISR(void)
{ {
if (dma_get_interrupt_flag(WS2812B_DMA, WS2812B_DMA_CH, DMA_TCIF)) { // transfer completed if (dma_get_interrupt_flag(WS2812B_DMA, WS2812B_DMA_CH, DMA_TCIF)) { // transfer completed

View File

@ -12,18 +12,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief library to drive a WS2812b LED chain (API)
/* this library is used to drive a WS2812b LED chain */ * @file led_ws2812b.h
/* peripherals used: SPI , timer, DMA (check source for details) */ * @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
* @note peripherals used: SPI @ref led_ws2812b_spi, timer @ref led_ws2812b_timer, DMA @ref led_ws2812b_dma
*/
#pragma once #pragma once
/* number of LEDs */ /** number of LEDs on the WS2812b strip */
#define WS2812B_LEDS 60 #define WS2812B_LEDS 60
/* set color of a single LED /** @brief setup WS2812b LED driver */
* transmission needs to be done separately */
void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue);
/* transmit colors to LEDs */
void ws2812b_transmit(void);
/* setup WS2812b LED controller */
void ws2812b_setup(void); void ws2812b_setup(void);
/** @brief set color of a single LED
* @param[in] led the LED number to set the color
* @param[in] red the red color value to set on the LED
* @param[in] green the green color value to set on the LED
* @param[in] blue the blue color value to set on the LED
* @note transmission needs to be done separately
*/
void ws2812b_set_rgb(uint16_t led, uint8_t red, uint8_t green, uint8_t blue);
/** @brief transmit color values to WS2812b LEDs */
void ws2812b_transmit(void);

View File

@ -12,11 +12,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** @file rtc_ds1307.c /** @brief library to communicate with the Maxim DS1307 I2C RTC IC (code)
* @file rtc_ds1307.c
* @author King Kévin <kingkevin@cuvoodoo.info> * @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016 * @date 2016
* @brief this library handles communication with the I2C RTC IC Maxim DS1307 * @note peripherals used: I2C @ref rtc_ds1307_i2c
* peripherals used: I2C @ref rtc_ds1307_i2c
*/ */
/* standard libraries */ /* standard libraries */
@ -34,26 +34,19 @@
#include "global.h" // global utilities #include "global.h" // global utilities
#include "rtc_ds1307.h" // RTC header and definitions #include "rtc_ds1307.h" // RTC header and definitions
/** @defgroup trc_ds1307_i2c I2C port used to communication with the DS1307 RTC IC /** @defgroup rtc_ds1307_i2c I2C peripheral used to communication with the DS1307 RTC IC
* @{ * @{
*/ */
/** I2C peripheral */ /** I2C peripheral */
#define I2C I2C1 #define I2C I2C1 /**< I2C peripheral */
/** I2C peripheral clock */ #define I2C_RCC RCC_I2C1 /**< I2C peripheral clock */
#define I2C_RCC RCC_I2C1 #define I2C_IRQ NVIC_I2C1_EV_IRQ /**< I2C peripheral interrupt */
/** I2C peripheral interrupt */ #define I2C_ISR i2c1_ev_isr /**< I2C event interrupt service routine */
#define I2C_IRQ NVIC_I2C1_EV_IRQ #define I2C_PORT GPIOB /**< I2C peripheral port */
/** I2C event interrupt service routine */ #define I2C_PIN_SDA GPIO_I2C1_SDA /**< I2C peripheral data pin (PB7) */
#define I2C_ISR i2c1_ev_isr #define I2C_PIN_SCL GPIO_I2C1_SCL /**< I2C peripheral clock pin (PB6) */
/** I2C peripheral port */
#define I2C_PORT GPIOB
/** I2C peripheral data pin (PB7) */
#define I2C_PIN_SDA GPIO_I2C1_SDA
/** I2C peripheral clock pin (PB6) */
#define I2C_PIN_SCL GPIO_I2C1_SCL
/** @} */ /** @} */
/** DS1307 I2C address (fixed) */ #define I2C_ADDR 0x68 /**< DS1307 I2C address (fixed to 0b1101000) */
#define I2C_ADDR 0x68 //0b1101000
void rtc_setup(void) void rtc_setup(void)
{ {
@ -413,6 +406,7 @@ bool rtc_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day
return rtc_write_memory(0, data, LENGTH(data)); // write time values on RTC return rtc_write_memory(0, data, LENGTH(data)); // write time values on RTC
} }
void I2C_ISR(void) { // I2C event ISR /** I2C event interrupt service routine */
void I2C_ISR(void) {
// do nothing except wake up // do nothing except wake up
} }

View File

@ -12,12 +12,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/** @file rtc_ds1307.h /** @brief library to communicate with the Maxim DS1307 I2C RTC IC (API)
* @file rtc_ds1307.h
* @author King Kévin <kingkevin@cuvoodoo.info> * @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016 * @date 2016
* @brief this library handles communication with the I2C RTC IC Maxim DS1307
* @todo control register and user RAM are not handled * @todo control register and user RAM are not handled
* peripherals used: I2C @ref rtc_ds1307_i2c * @note peripherals used: I2C @ref rtc_ds1307_i2c
*/ */
#pragma once #pragma once
@ -42,15 +42,15 @@ uint8_t rtc_read_minutes(void);
*/ */
uint8_t rtc_read_hours(void); uint8_t rtc_read_hours(void);
/** @brief read day from RTC IC /** @brief read day from RTC IC
* @return day (1-7) of the current time, 1 being Sunday * @return day of the week (1-7, 1 is Sunday) of the current time, 1 being Sunday
*/ */
uint8_t rtc_read_day(void); uint8_t rtc_read_day(void);
/** @brief read date from RTC IC /** @brief read date from RTC IC
* @return date (day of the month, 1-31) of the current time * @return day of the month (1-31) of the current time
*/ */
uint8_t rtc_read_date(void); uint8_t rtc_read_date(void);
/** @brief read month from RTC IC /** @brief read month from RTC IC
* @return month (1-12) of the current time * @return month of the year (1-12) of the current time
*/ */
uint8_t rtc_read_month(void); uint8_t rtc_read_month(void);
/** @brief read year from RTC IC /** @brief read year from RTC IC
@ -70,48 +70,48 @@ bool rtc_oscillator_disable(void);
*/ */
bool rtc_oscillator_enable(void); bool rtc_oscillator_enable(void);
/** @brief write seconds into RTC IC /** @brief write seconds into RTC IC
* @param[in] number of seconds (0-59) * @param[in] seconds number of seconds (0-59)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_seconds(uint8_t seconds); bool rtc_write_seconds(uint8_t seconds);
/** @brief write minutes into RTC IC /** @brief write minutes into RTC IC
* @param[in] number of minutes (0-59) * @param[in] minutes number of minutes (0-59)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_minutes(uint8_t minutes); bool rtc_write_minutes(uint8_t minutes);
/** @brief write hours into RTC IC /** @brief write hours into RTC IC
* @param[in] number of hours (0-23) * @param[in] hours number of hours (0-23)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_hours(uint8_t hours); bool rtc_write_hours(uint8_t hours);
/** @brief write day into RTC IC /** @brief write day into RTC IC
* @param[in] day (1-7, 1 is Sunday) * @param[in] day day of the week (1-7, 1 is Sunday)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_day(uint8_t day); bool rtc_write_day(uint8_t day);
/** @brief write date into RTC IC /** @brief write date into RTC IC
* @param[in] date (day of the month, 1-31) * @param[in] date day of the month (1-31)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_date(uint8_t date); bool rtc_write_date(uint8_t date);
/** @brief write month into RTC IC /** @brief write month into RTC IC
* @param[in] month (1-12) * @param[in] month month of the year (1-12)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_month(uint8_t month); bool rtc_write_month(uint8_t month);
/** @brief write year into RTC IC /** @brief write year into RTC IC
* @param[in] year (2000-2099) * @param[in] year year (2000-2099)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_year(uint16_t year); bool rtc_write_year(uint16_t year);
/** @brief write time into RTC IC /** @brief write time into RTC IC
* @param[in] number of seconds (0-59) * @param[in] seconds number of seconds (0-59)
* @param[in] number of minutes (0-59) * @param[in] minutes number of minutes (0-59)
* @param[in] number of hours (0-23) * @param[in] hours number of hours (0-23)
* @param[in] day (1-7, 1 is Sunday) * @param[in] day day of the week (1-7, 1 is Sunday)
* @param[in] date (day of the month, 1-31) * @param[in] date day of the month (1-31)
* @param[in] month (1-12) * @param[in] month month of the year (1-12)
* @param[in] year (2000-2099) * @param[in] year year (2000-2099)
* @return if write succeeded * @return if write succeeded
*/ */
bool rtc_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint16_t year); bool rtc_write_time(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day, uint8_t date, uint8_t month, uint16_t year);

View File

@ -12,9 +12,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief library for USART communication (code)
/* this library handles USART communication */ * @file usart.c
/* peripherals used: USART (check source for details) */ * @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
* @note peripherals used: USART @ref usart
*/
/* standard libraries */ /* standard libraries */
#include <stdint.h> // standard integer types #include <stdint.h> // standard integer types
@ -30,18 +33,19 @@
#include "usart.h" // USART header and definitions #include "usart.h" // USART header and definitions
/* which USART to use */ /** @defgroup usart USART peripheral used for UART communication
#define USART USART1 * @{
#define USART_RCC RCC_USART1 */
#define USART_IRQ NVIC_USART1_IRQ #define USART USART1 /**< USART peripheral */
#define USART_PORT GPIOA #define USART_RCC RCC_USART1 /**< USART peripheral clock */
#define USART_PIN_TX GPIO_USART1_TX #define USART_IRQ NVIC_USART1_IRQ /**< USART peripheral interrupt signal */
#define USART_PIN_RX GPIO_USART1_RX #define USART_ISR usart1_isr /**< USART interrupt service routine */
#define USART_PORT GPIOA /**< USART port */
#define USART_PIN_TX GPIO_USART1_TX /**< USART transmit pin (PA9) */
#define USART_PIN_RX GPIO_USART1_RX /**< USART receive pin (PA10) */
/** @} */
/* serial baudrate, in bits per second (with 8N1 8 bits, no parity bit, 1 stop bit settings) */ #define USART_BAUDRATE 115200 /**< serial baudrate, in bits per second (with 8N1 8 bits, no parity bit, 1 stop bit settings) */
#define USART_BAUDRATE 115200
/* RX and TX buffer sizes */
#define USART_BUFFER 128
/* input and output ring buffer, indexes, and available memory */ /* input and output ring buffer, indexes, and available memory */
static uint8_t rx_buffer[USART_BUFFER] = {0}; static uint8_t rx_buffer[USART_BUFFER] = {0};
@ -50,10 +54,8 @@ static volatile uint8_t rx_used = 0;
static uint8_t tx_buffer[USART_BUFFER] = {0}; static uint8_t tx_buffer[USART_BUFFER] = {0};
static volatile uint8_t tx_i = 0; static volatile uint8_t tx_i = 0;
static volatile uint8_t tx_used = 0; static volatile uint8_t tx_used = 0;
/* show the user how much data received over USART is ready */
volatile uint8_t usart_received = 0; // same as rx_used, but since the user can write this variable we don't rely on it volatile uint8_t usart_received = 0; // same as rx_used, but since the user can write this variable we don't rely on it
/* setup USART port */
void usart_setup(void) void usart_setup(void)
{ {
/* enable USART I/O peripheral */ /* enable USART I/O peripheral */
@ -82,14 +84,12 @@ void usart_setup(void)
usart_received = 0; usart_received = 0;
} }
/* put character on USART (blocking) */
void usart_putchar_blocking(char c) void usart_putchar_blocking(char c)
{ {
usart_flush(); // empty buffer first usart_flush(); // empty buffer first
usart_send_blocking(USART, c); // send character usart_send_blocking(USART, c); // send character
} }
/* ensure all data has been transmitted (blocking) */
void usart_flush(void) void usart_flush(void)
{ {
while (tx_used) { // idle until buffer is empty while (tx_used) { // idle until buffer is empty
@ -98,7 +98,6 @@ void usart_flush(void)
usart_wait_send_ready(USART); // wait until transmit register is empty (transmission might not be complete) usart_wait_send_ready(USART); // wait until transmit register is empty (transmission might not be complete)
} }
/* get character from USART (blocking) */
char usart_getchar(void) char usart_getchar(void)
{ {
while (!rx_used) { // idle until data is available while (!rx_used) { // idle until data is available
@ -111,7 +110,6 @@ char usart_getchar(void)
return to_return; return to_return;
} }
/* put character on USART (non-blocking until buffer is full) */
void usart_putchar_nonblocking(char c) void usart_putchar_nonblocking(char c)
{ {
while (tx_used>=sizeof(tx_buffer)) { // idle until buffer has some space while (tx_used>=sizeof(tx_buffer)) { // idle until buffer has some space
@ -123,14 +121,9 @@ void usart_putchar_nonblocking(char c)
usart_enable_tx_interrupt(USART); // enable transmit interrupt usart_enable_tx_interrupt(USART); // enable transmit interrupt
} }
#if (USART==USART1) /** @brief USART interrupt service routine called when data has been transmitted or received */
void usart1_isr(void) void USART_ISR(void)
#elif (USART==USART2) {
void usart2_isr(void)
#elif (USART==USART3)
void usart3_isr(void)
#endif
{ // USART interrupt
if (usart_get_interrupt_source(USART, USART_SR_TXE)) { // data has been transmitted if (usart_get_interrupt_source(USART, USART_SR_TXE)) { // data has been transmitted
if (!tx_used) { // no data in the buffer to transmit if (!tx_used) { // no data in the buffer to transmit
usart_disable_tx_interrupt(USART); // disable transmit interrupt usart_disable_tx_interrupt(USART); // disable transmit interrupt

View File

@ -12,21 +12,36 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief library for USART communication (API)
/* this library handles USART communication */ * @file usart.h
/* peripherals used: USART (check source for details) */ * @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
* @note peripherals used: USART @ref usart
*/
#pragma once #pragma once
/* show the user how much received is available */ /** transmit and receive buffer sizes */
#define USART_BUFFER 128
/** how many bytes available in the received buffer since last read */
extern volatile uint8_t usart_received; extern volatile uint8_t usart_received;
/* setup USART port */ /** @brief setup USART peripheral */
void usart_setup(void); void usart_setup(void);
/* put character on USART (blocking) */ /** @brief send character over USART (blocking)
* @param[in] c character to send
* @note blocks until character transmission started */
void usart_putchar_blocking(char c); void usart_putchar_blocking(char c);
/* ensure all data has been transmitted (blocking) */ /** @brief ensure all data has been transmitted (blocking)
* @note block until all data has been transmitted
*/
void usart_flush(void); void usart_flush(void);
/* get character from USART (blocking) */ /** @brief get character received over USART (blocking)
* @return character received over USART
* @note blocks until character is received over USART when received buffer is empty
*/
char usart_getchar(void); char usart_getchar(void);
/* put character on USART (non-blocking until buffer is full) */ /** @brief send character over USART (non-blocking)
* @param[in] c character to send
* @note blocks if transmit buffer is full, else puts in buffer and returns
*/
void usart_putchar_nonblocking(char c); void usart_putchar_nonblocking(char c);

View File

@ -12,8 +12,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief library for USB CDC ACM communication (code)
/* this library handles the USB CDC ACM */ * @file usb_cdcacm.c
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
*/
/* standard libraries */ /* standard libraries */
#include <stdint.h> // standard integer types #include <stdint.h> // standard integer types
@ -31,8 +34,8 @@
#include "usb_cdcacm.h" // USB CDC ACM header and definitions #include "usb_cdcacm.h" // USB CDC ACM header and definitions
/* USB devices descriptor /** @brief USB CDC ACM device descriptor
* as defined in USB CDC specification section 5 * @note as defined in USB CDC specification section 5
*/ */
static const struct usb_device_descriptor device_descriptor = { static const struct usb_device_descriptor device_descriptor = {
.bLength = USB_DT_DEVICE_SIZE, // the size of this header in bytes, 18 .bLength = USB_DT_DEVICE_SIZE, // the size of this header in bytes, 18
@ -51,6 +54,9 @@ static const struct usb_device_descriptor device_descriptor = {
.bNumConfigurations = 1, // the number of possible configurations this device has .bNumConfigurations = 1, // the number of possible configurations this device has
}; };
/** @brief USB CDC ACM data endpoints
* @note as defined in USB CDC specification section 5
*/
static const struct usb_endpoint_descriptor data_endpoints[] = {{ static const struct usb_endpoint_descriptor data_endpoints[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes .bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes
.bDescriptorType = USB_DT_ENDPOINT, // a value of 5 indicates that this describes an endpoint .bDescriptorType = USB_DT_ENDPOINT, // a value of 5 indicates that this describes an endpoint
@ -67,9 +73,8 @@ static const struct usb_endpoint_descriptor data_endpoints[] = {{
.bInterval = 1, // the frequency, in number of frames, that we're going to be sending data .bInterval = 1, // the frequency, in number of frames, that we're going to be sending data
}}; }};
/* This notification endpoint isn't implemented. According to CDC spec its /** @brief USB CDC ACM communication endpoints
* optional, but its absence causes a NULL pointer dereference in Linux * @note This notification endpoint isn't implemented. According to CDC spec its optional, but its absence causes a NULL pointer dereference in Linux cdc_acm driver
* cdc_acm driver.
*/ */
static const struct usb_endpoint_descriptor communication_endpoints[] = {{ static const struct usb_endpoint_descriptor communication_endpoints[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes .bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes
@ -80,8 +85,8 @@ static const struct usb_endpoint_descriptor communication_endpoints[] = {{
.bInterval = 255, // the frequency, in number of frames, that we're going to be sending data .bInterval = 255, // the frequency, in number of frames, that we're going to be sending data
}}; }};
/* functional descriptor /** @brief USB CDC ACM functional descriptor
* as defined in USB CDC specification section 5.2.3 * @note as defined in USB CDC specification section 5.2.3
*/ */
static const struct { static const struct {
struct usb_cdc_header_descriptor header; struct usb_cdc_header_descriptor header;
@ -117,8 +122,8 @@ static const struct {
}, },
}; };
/* communication class interface descriptor /** @brief USB CDC interface descriptor
* as defined in USB CDC specification section 5.1.3 * @note as defined in USB CDC specification section 5.1.3
*/ */
static const struct usb_interface_descriptor communication_interface[] = {{ static const struct usb_interface_descriptor communication_interface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
@ -137,8 +142,8 @@ static const struct usb_interface_descriptor communication_interface[] = {{
.extralen = sizeof(cdcacm_functional_descriptors), .extralen = sizeof(cdcacm_functional_descriptors),
}}; }};
/* data class interface descriptor /** @brief USB CDC ACM data class interface descriptor
* as defined in USB CDC specification section 5.1.3 * @note as defined in USB CDC specification section 5.1.3
*/ */
static const struct usb_interface_descriptor data_interface[] = {{ static const struct usb_interface_descriptor data_interface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
@ -154,6 +159,7 @@ static const struct usb_interface_descriptor data_interface[] = {{
.endpoint = data_endpoints, .endpoint = data_endpoints,
}}; }};
/** @brief USB CDC ACM interface descriptor */
static const struct usb_interface interfaces[] = {{ static const struct usb_interface interfaces[] = {{
.num_altsetting = 1, .num_altsetting = 1,
.altsetting = communication_interface, .altsetting = communication_interface,
@ -162,6 +168,7 @@ static const struct usb_interface interfaces[] = {{
.altsetting = data_interface, .altsetting = data_interface,
}}; }};
/** @brief USB CDC ACM configuration descriptor */
static const struct usb_config_descriptor config = { static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, // the length of this header in bytes .bLength = USB_DT_CONFIGURATION_SIZE, // the length of this header in bytes
.bDescriptorType = USB_DT_CONFIGURATION, // a value of 2 indicates that this is a configuration descriptor .bDescriptorType = USB_DT_CONFIGURATION, // a value of 2 indicates that this is a configuration descriptor
@ -175,17 +182,19 @@ static const struct usb_config_descriptor config = {
.interface = interfaces, // pointer to an array of interfaces .interface = interfaces, // pointer to an array of interfaces
}; };
/* string table (starting with index 1) */ /** @brief USB string table
const char *usb_strings[] = { * @note starting with index 1
*/
static const char *usb_strings[] = {
"CuVoodoo", "CuVoodoo",
"CDC-ACM", "CDC-ACM",
"STM32F1", "STM32F1",
}; };
/* buffer to be used for control requests */ /** buffer to be used for control requests */
static uint8_t usbd_control_buffer[128]; static uint8_t usbd_control_buffer[128];
/* structure holding all the info related to the USB device */ /** structure holding all the info related to the USB device */
static usbd_device *usb_device; static usbd_device *usb_device;
/* input and output ring buffer, indexes, and available memory */ /* input and output ring buffer, indexes, and available memory */
@ -195,10 +204,9 @@ static volatile uint8_t rx_used = 0;
static uint8_t tx_buffer[CDCACM_BUFFER] = {0}; static uint8_t tx_buffer[CDCACM_BUFFER] = {0};
static volatile uint8_t tx_i = 0; static volatile uint8_t tx_i = 0;
static volatile uint8_t tx_used = 0; static volatile uint8_t tx_used = 0;
/* show the user how much data received over USB is ready */
volatile uint8_t cdcacm_received = 0; // same as rx_used, but since the user can write this variable we don't rely on it volatile uint8_t cdcacm_received = 0; // same as rx_used, but since the user can write this variable we don't rely on it
/* disconnect USB by pulling down D+ to for re-enumerate */ /** @brief disconnect USB by pulling down D+ to for re-enumerate */
static void usb_disconnect(void) static void usb_disconnect(void)
{ {
/* short USB disconnect to force re-enumerate */ /* short USB disconnect to force re-enumerate */
@ -222,6 +230,9 @@ static void usb_disconnect(void)
#endif #endif
} }
/** @brief incoming USB CDC ACM control request
* @note resets device when configured with 5 bits
*/
static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
{ {
(void)complete; (void)complete;
@ -338,7 +349,6 @@ void cdcacm_setup(void)
usbd_ep_write_packet(usb_device, 0x82, NULL, 0); usbd_ep_write_packet(usb_device, 0x82, NULL, 0);
} }
/* get character from USB CDC ACM (blocking) */
char cdcacm_getchar(void) char cdcacm_getchar(void)
{ {
while (!rx_used) { // idle until data is available while (!rx_used) { // idle until data is available
@ -351,7 +361,6 @@ char cdcacm_getchar(void)
return to_return; return to_return;
} }
/* put character on USB CDC ACM (blocking) */
void cdcacm_putchar(char c) void cdcacm_putchar(char c)
{ {
if (tx_used<sizeof(tx_buffer)) { // buffer not full if (tx_used<sizeof(tx_buffer)) { // buffer not full
@ -364,10 +373,12 @@ void cdcacm_putchar(char c)
usbd_ep_write_packet(usb_device, 0x82, NULL, 0); // trigger tx (not sure why cdcacm_data_tx_cb doesn't work else) usbd_ep_write_packet(usb_device, 0x82, NULL, 0); // trigger tx (not sure why cdcacm_data_tx_cb doesn't work else)
} }
/** @brief USB interrupt service routine called on wake-up event */
void usb_wakeup_isr(void) { void usb_wakeup_isr(void) {
usbd_poll(usb_device); usbd_poll(usb_device);
} }
/** @brief USB interrupt service routine called when data is received */
void usb_lp_can_rx0_isr(void) { void usb_lp_can_rx0_isr(void) {
usbd_poll(usb_device); usbd_poll(usb_device);
} }

View File

@ -12,18 +12,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/* Copyright (c) 2016 King Kévin <kingkevin@cuvoodoo.info> */ /** @brief library for USB CDC ACM communication (API)
/* this library handles the USB CDC ACM */ * @file usb_cdcacm.h
* @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016
*/
#pragma once #pragma once
/* RX buffer size */ /** transmit and receive buffer sizes */
#define CDCACM_BUFFER 128 #define CDCACM_BUFFER 128
/* show the user how much received is available */ /** how many bytes available in the received buffer since last read */
extern volatile uint8_t cdcacm_received; extern volatile uint8_t cdcacm_received;
/* setup USB CDC ACM */ /** @brief setup USB CDC ACM peripheral */
void cdcacm_setup(void); void cdcacm_setup(void);
/* get character from USB CDC ACM (blocking) */ /** @brief get character received over USB (blocking)
* @return character received over USB
* @note blocks until character is received over USB when received buffer is empty
*/
char cdcacm_getchar(void); char cdcacm_getchar(void);
/* put character on USB CDC ACM (blocking) */ /** @brief send character over USB (non-blocking)
* @param[in] c character to send
* @note blocks if transmit buffer is full, else puts in buffer and returns
*/
void cdcacm_putchar(char c); void cdcacm_putchar(char c);

24
main.c
View File

@ -13,11 +13,12 @@
* *
*/ */
/** @file main.c /** @file main.c
* @author King Kévin <kingkevin@cuvoodoo.info> @author King Kévin <kingkevin@cuvoodoo.info>
* @date 2016 @date 2016
* @brief show the time on a LED strip @brief show the time on a LED strip
* the LED strip consists of 60 WS2812b LEDs
* the time is read from a DS1307 RTC module The LED strip consists of 60 WS2812b LEDs.
The time is read from a DS1307 RTC module.
*/ */
/* standard libraries */ /* standard libraries */
@ -42,8 +43,11 @@
#include "led_ws2812b.h" // WS2812b LEDs utilities #include "led_ws2812b.h" // WS2812b LEDs utilities
#include "rtc_ds1307.h" // Real Time Clock DS1307 utilities #include "rtc_ds1307.h" // Real Time Clock DS1307 utilities
/* flag set in interrupts to be processed in main task */ /** @defgroup main_flags flag set in interrupts to be processed in main task
volatile bool button_flag = false; // button has been pressed @{
*/
volatile bool button_flag = false; /**< flag set if board user button has been pressed */
/** @} */
/** the number of ticks in one second /** the number of ticks in one second
* @note the other values are derived from this value @ref main_ticks * @note the other values are derived from this value @ref main_ticks
@ -63,7 +67,8 @@ const uint32_t ticks_hour = 60*60*TICKS_PER_SECOND;
const uint32_t ticks_midday = 12*60*60*TICKS_PER_SECOND; const uint32_t ticks_midday = 12*60*60*TICKS_PER_SECOND;
/** @} */ /** @} */
uint8_t clock_leds[WS2812B_LEDS*3] = {0}; // RGB values for the WS2812b clock LEDs /** RGB values for the WS2812b clock LEDs */
uint8_t clock_leds[WS2812B_LEDS*3] = {0};
/** @brief default printf output */ /** @brief default printf output */
int _write(int file, char *ptr, int len) int _write(int file, char *ptr, int len)
@ -215,6 +220,9 @@ static void leds_set(void)
} }
} }
/** @brief program entry point
* this is the firmware function started by the micro-controller
*/
int main(void) int main(void)
{ {
SCB_VTOR = (uint32_t) 0x08002000; // relocate vector table because of the bootloader SCB_VTOR = (uint32_t) 0x08002000; // relocate vector table because of the bootloader