main firmware: WIP
very rough WIP of main badge code. some LED programs are here, and it will build if the btn code is excluded.
This commit is contained in:
178
badge_firmware/code/inc/adxl.h
Normal file
178
badge_firmware/code/inc/adxl.h
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* adxl.h
|
||||
*
|
||||
* Created on: Jul 18, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_ADXL_H_
|
||||
#define CODE_INC_ADXL_H_
|
||||
|
||||
|
||||
|
||||
#include "hk32f030m.h"
|
||||
#include "spi.h"
|
||||
|
||||
|
||||
|
||||
typedef struct adxl345_axes {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
} adxl345_axes;
|
||||
|
||||
|
||||
|
||||
#define ADXL345_SPI_DEV SPI1
|
||||
|
||||
#define ADXL345_SPI_CS_PORT GPIOC
|
||||
#define ADXL345_SPI_CS_PIN GPIO_Pin_4
|
||||
|
||||
#define ADXL345_MODE_RD 0x80
|
||||
#define ADXL345_MODE_WR 0x00
|
||||
#define ADXL345_MODE_MB 0x40 // multi-byte read or write
|
||||
|
||||
#define ADXL345_REG_DEVID 0x00 // read-only, should == 0xE5
|
||||
#define ADXL345_REG_THRESH_TAP 0x1D // 0xff = 16g
|
||||
#define ADXL345_REG_OFSX 0x1E // 0x7f = 2g
|
||||
#define ADXL345_REG_OFSY 0x1F // ""
|
||||
#define ADXL345_REG_OFSZ 0x20 // ""
|
||||
#define ADXL345_REG_TAP_DUR 0x21 // 625usec/LSB, 0 disables
|
||||
#define ADXL345_REG_TAP_LATENTCY 0x22 // 1.25ms/LSB, 0 disables double tap
|
||||
#define ADXL345_REG_TAP_WINDOW 0x23 // 1.25ms/LSB, 0 disables double tap
|
||||
#define ADXL345_REG_THRESH_ACT 0x24 // 0xFF = 16g
|
||||
#define ADXL345_REG_THRESH_INACT 0x25 // 0xFF = 16g
|
||||
#define ADXL345_REG_TIME_INACT 0x26 // 1sec/LSB
|
||||
#define ADXL345_REG_ACT_INACT_CTL 0x27
|
||||
#define ADXL345_REG_THRESH_FF 0x28 // 0xFF = 16g, recommend 0x05-0x09
|
||||
#define ADXL345_REG_TIME_FF 0x29 // 5ms/LSB, recommend 0x14-0x46
|
||||
#define ADXL345_REG_TAP_AXES 0x2A
|
||||
#define ADXL345_REG_ACT_TAP_STATUS 0x2B // read-only
|
||||
#define ADXL345_REG_BW_RATE 0x2C
|
||||
#define ADXL345_REG_POWER_CTL 0x2D
|
||||
#define ADXL345_REG_INT_ENABLE 0x2E
|
||||
#define ADXL345_REG_INT_MAP 0x2F
|
||||
#define ADXL345_REG_INT_SOURCE 0x30 // read-only
|
||||
#define ADXL345_REG_DATA_FORMAT 0x31
|
||||
#define ADXL345_REG_DATAX0 0x32 // read-only
|
||||
#define ADXL345_REG_DATAX1 0x33 // read-only
|
||||
#define ADXL345_REG_DATAY0 0x34 // read-only
|
||||
#define ADXL345_REG_DATAY1 0x35 // read-only
|
||||
#define ADXL345_REG_DATAZ0 0x36 // read-only
|
||||
#define ADXL345_REG_DATAZ1 0x37 // read-only
|
||||
#define ADXL345_REG_FIFO_CTL 0x38
|
||||
#define ADXL345_REG_FIFO_STATUS 0x39
|
||||
|
||||
#define ADXL345_TAP_AXES_X_ENABLE (1 << 2)
|
||||
#define ADXL345_TAP_AXES_Y_ENABLE (1 << 1)
|
||||
#define ADXL345_TAP_AXES_Z_ENABLE (1 << 0)
|
||||
|
||||
#define ADXL345_CTL_ACT_AC (1 << 7)
|
||||
#define ADXL345_CTL_ACT_X_ENA (1 << 6)
|
||||
#define ADXL345_CTL_ACT_Y_ENA (1 << 5)
|
||||
#define ADXL345_CTL_ACT_Z_ENA (1 << 4)
|
||||
#define ADXL345_CTL_INACT_AC (1 << 3)
|
||||
#define ADXL345_CTL_INACT_X_ENA (1 << 2)
|
||||
#define ADXL345_CTL_INACT_Y_ENA (1 << 1)
|
||||
#define ADXL345_CTL_INACT_Z_ENA (1 << 0)
|
||||
|
||||
#define ADXL345_ACT_TAP_ACT_X (1 << 6)
|
||||
#define ADXL345_ACT_TAP_ACT_Y (1 << 5)
|
||||
#define ADXL345_ACT_TAP_ACT_Z (1 << 4)
|
||||
#define ADXL345_ACT_TAP_TAP_X (1 << 2)
|
||||
#define ADXL345_ACT_TAP_TAP_Y (1 << 1)
|
||||
#define ADXL345_ACT_TAP_TAP_Z (1 << 0)
|
||||
|
||||
#define ADXL345_INT_DATA_READY (1 << 7)
|
||||
#define ADXL345_INT_SINGLE_TAP (1 << 6)
|
||||
#define ADXL345_INT_DOUBLE_TAP (1 << 5)
|
||||
#define ADXL345_INT_ACTIVITY (1 << 4)
|
||||
#define ADXL345_INT_INACTIVITY (1 << 3)
|
||||
#define ADXL345_INT_FREE_FALL (1 << 2)
|
||||
#define ADXL345_INT_WATERMARK (1 << 1)
|
||||
#define ADXL345_INT_OVERRUN (1 << 0)
|
||||
#define ADXL345_INT_ALL 0xff
|
||||
|
||||
#define ADXL345_DFMT_SELF_TEST (1 << 7)
|
||||
#define ADXL345_DFMT_SPI (1 << 6)
|
||||
#define ADXL345_DFMT_INT_INVERT (1 << 5)
|
||||
#define ADXL345_DFMT_FULL_RES (1 << 3)
|
||||
#define ADXL345_DFMT_JUSTIFY (1 << 2)
|
||||
#define ADXL345_DFMT_RANGE (3 << 0)
|
||||
|
||||
#define ADXL345_INTR_ACTIVE_HI 1
|
||||
#define ADXL345_INTR_ACTIVE_LO 0
|
||||
|
||||
#define ADXL345_BW_RATE_LOW_POWER (1 << 4)
|
||||
#define ADXL345_BW_RATE_MASK (0xf)
|
||||
|
||||
#define ADXL345_BW_RATE_3200 0x0f
|
||||
#define ADXL345_BW_RATE_1600 0x0e
|
||||
#define ADXL345_BW_RATE_800 0x0d
|
||||
#define ADXL345_BW_RATE_400 0x0c // low-power compat
|
||||
#define ADXL345_BW_RATE_200 0x0b // low-power compat
|
||||
#define ADXL345_BW_RATE_100 0x0a // low-power compat
|
||||
#define ADXL345_BW_RATE_50 0x09 // low-power compat
|
||||
#define ADXL345_BW_RATE_25 0x08 // low-power compat
|
||||
#define ADXL345_BW_RATE_12_5 0x07 // low-power compat
|
||||
#define ADXL345_BW_RATE_6_25 0x06
|
||||
#define ADXL345_BW_RATE_3_13 0x05
|
||||
#define ADXL345_BW_RATE_1_56 0x04
|
||||
#define ADXL345_BW_RATE_0_78 0x03
|
||||
#define ADXL345_BW_RATE_0_39 0x02
|
||||
#define ADXL345_BW_RATE_0_20 0x01
|
||||
#define ADXL345_BW_RATE_0_10 0x00
|
||||
|
||||
#define ADXL345_POWER_CTL_LINK (1 << 5)
|
||||
#define ADXL345_POWER_CTL_AUTO_SLP (1 << 4)
|
||||
#define ADXL345_POWER_CTL_MEASURE (1 << 3)
|
||||
#define ADXL345_POWER_CTL_SLEEP (1 << 2)
|
||||
#define ADXL345_POWER_CTL_WAKEUP_MASK (2 << 0)
|
||||
|
||||
#define ADXL345_POWER_CTL_WAKEUP_1HZ (0x03)
|
||||
#define ADXL345_POWER_CTL_WAKEUP_2HZ (0x02)
|
||||
#define ADXL345_POWER_CTL_WAKEUP_4HZ (0x01)
|
||||
#define ADXL345_POWER_CTL_WAKEUP_8HZ (0x00)
|
||||
|
||||
#define ADXL345_DATA_FORMAT_SELF_TEST (1 << 7)
|
||||
#define ADXL345_DATA_FORMAT_SPI (1 << 6)
|
||||
#define ADXL345_DATA_FORMAT_INT_INV (1 << 5)
|
||||
#define ADXL345_DATA_FORMAT_FULL_RES (1 << 3)
|
||||
#define ADXL345_DATA_FORMAT_JUSTIFY (1 << 2)
|
||||
#define ADXL345_DATA_FORMAT_RANGE_MASK (2 << 0)
|
||||
|
||||
#define ADXL345_DATA_FORMAT_RANGE_16G (0x03)
|
||||
#define ADXL345_DATA_FORMAT_RANGE_8G (0x03)
|
||||
#define ADXL345_DATA_FORMAT_RANGE_4G (0x03)
|
||||
#define ADXL345_DATA_FORMAT_RANGE_2G (0x03)
|
||||
|
||||
// r = receive buffer, t = transmit buffer, s = length
|
||||
#define adxl_spi_xfer(r, t, s) ADXL345_SPI_CS_PORT->BRR = ADXL345_SPI_CS_PIN; \
|
||||
spi_mosi_sel(SPI_MOSI_SPI); \
|
||||
spi_xfer(t, r, s, 0); \
|
||||
ADXL345_SPI_CS_PORT->BSRR = ADXL345_SPI_CS_PIN;
|
||||
|
||||
|
||||
|
||||
extern adxl345_axes adxl;
|
||||
extern uint16_t movement_worst;
|
||||
|
||||
|
||||
|
||||
void adxl345_init();
|
||||
void adxl345_tick();
|
||||
|
||||
void adxl345_get_axes(struct adxl345_axes *adxl);
|
||||
int8_t adxl345_get_rotation(struct adxl345_axes *adxl);
|
||||
|
||||
int16_t adxl345_movement();
|
||||
|
||||
void adxl345_set_reg8(uint8_t reg, uint8_t val);
|
||||
|
||||
void adxl345_set_intr(uint8_t int2_map, uint8_t interrupt_flags);
|
||||
void adxl345_set_intr_polarity(uint8_t active_polarity);
|
||||
uint8_t adxl345_get_intr_flag();
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_ADXL_H_ */
|
||||
68
badge_firmware/code/inc/btn.h
Normal file
68
badge_firmware/code/inc/btn.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* btn.h
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_BTN_H_
|
||||
#define CODE_INC_BTN_H_
|
||||
|
||||
|
||||
#define BTN_MODE 0
|
||||
#define BTN_PROG 1
|
||||
#define BTN_SET 2
|
||||
|
||||
#define BTN_COUNT 3
|
||||
|
||||
#define BTN_PUSH (1 << 0)
|
||||
#define BTN_HELD (1 << 1)
|
||||
#define BTN_RELEASE (1 << 2)
|
||||
|
||||
#define BTN_PUSH_CB (1 << 4)
|
||||
#define BTN_HELD_CB (1 << 5)
|
||||
#define BTN_RELEASE_CB (1 << 6)
|
||||
|
||||
#define BTN_DEBOUNCE 11 // how many button ticks to wait before registering press
|
||||
#define BTN_MAX_HOLD (512*30) // longest reported / processed hold time (30s)
|
||||
#define BTN_HOLD_SHIFT 6 // rshift value to get 1/16th sec hold time
|
||||
|
||||
|
||||
|
||||
typedef struct Btn_t {
|
||||
uint16_t state; // current state of button (pushed, held, callback done, etc)
|
||||
uint16_t held; // current hold counts, in button tickrate
|
||||
uint16_t hold_thresh; // hold time trigger threshold in 1/16 second increments
|
||||
uint16_t hold_retrig; // hold time retrigger threshold in button ticks, 0 disables
|
||||
uint16_t hold_rt_ctr; // hold retrigger counter
|
||||
|
||||
void (*push_cb)();
|
||||
void (*held_cb)();
|
||||
void (*release_cb)();
|
||||
} Btn_t;
|
||||
|
||||
/*
|
||||
* as long as button is pushed, .held will be incrementing
|
||||
* when .held exceeds debounce, a BTN_PUSH event will occur and push_cb will be called
|
||||
* .held will continue to increment while being held until BTN_MAX_HOLD is reached
|
||||
* when .hold_thresh is matched, a BTN_HELD event will occur and held_cb will be called
|
||||
* at this point, .hold_rt_ctr will begin counting with each button tick
|
||||
* when .hold_rt_ctr matches .hold_retrig, held_cb will be called again, and .hold_rt_ctr will be 0'd
|
||||
* even after .held stops counting, the .hold_rt_ctr will continue to run
|
||||
* if .hold_thresh is 0, then no BTN_HELD event will occur, and thus no retriggering either
|
||||
* if .hold_retrig is 0, then BTN_HELD will occur, but retriggers will not occur
|
||||
* upon release, BTN_RELEASED event will occur and release_cb will be called
|
||||
* after finishing release callback, .state will be cleared, .held will be 0
|
||||
*/
|
||||
|
||||
|
||||
|
||||
extern Btn_t btn[BTN_COUNT];
|
||||
|
||||
|
||||
void btn_init();
|
||||
void btn_tick();
|
||||
void btn_callback();
|
||||
|
||||
|
||||
#endif /* CODE_INC_BTN_H_ */
|
||||
108
badge_firmware/code/inc/hk32f030m_conf.h
Normal file
108
badge_firmware/code/inc/hk32f030m_conf.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hk32f030m_conf.h
|
||||
* @brief configuration file.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __HK32F030M_CONF_H
|
||||
#define __HK32F030M_CONF_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
/* ########################## HSE/HSI Values adaptation ##################### */
|
||||
/**
|
||||
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
|
||||
* This value is used by the RCC module to compute the system frequency
|
||||
* (when HSE is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#define EXTCLK_VALUE ((uint32_t)32000000) /*!< Value of the External oscillator in Hz */
|
||||
|
||||
/**
|
||||
* @brief Internal High Speed oscillator (HSI) value.
|
||||
* This value is used by the RCC module to compute the system frequency
|
||||
* (when HSI is used as system clock source, directly or through the PLL).
|
||||
*/
|
||||
#define HSI_VALUE ((uint32_t)32000000) /*!< Value of the Internal oscillator in Hz */
|
||||
|
||||
/**
|
||||
* @brief In the following line adjust the Internal High Speed oscillator (HSI) Startup
|
||||
* Timeout value
|
||||
*/
|
||||
#define HSI_STARTUP_TIMEOUT ((uint32_t)0xFFFF) /*!< Time out for start up */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Internal Low Speed oscillator (LSI) value.
|
||||
*/
|
||||
#define LSI_VALUE ((uint32_t)128000)
|
||||
/*!< Value of the Internal Low Speed oscillator in Hz
|
||||
The real value may vary depending on the variations */
|
||||
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Include module's header file
|
||||
*/
|
||||
|
||||
#include "hk32f030m_rcc.h"
|
||||
//#include "hk32f030m_crc.h"
|
||||
#include "hk32f030m_exti.h"
|
||||
#include "hk32f030m_flash.h"
|
||||
#include "hk32f030m_gpio.h"
|
||||
#include "hk32f030m_misc.h"
|
||||
//#include "hk32f030m_adc.h"
|
||||
#include "hk32f030m_syscfg.h"
|
||||
//#include "hk32f030m_def.h"
|
||||
//#include "hk32f030m_i2c.h"
|
||||
//#include "hk32f030m_iwdg.h"
|
||||
#include "hk32f030m_pwr.h"
|
||||
#include "hk32f030m_spi.h"
|
||||
#include "hk32f030m_tim.h"
|
||||
//#include "hk32f030m_usart.h"
|
||||
//#include "hk32f030m_iwdg.h"
|
||||
//#include "hk32f030m_wwdg.h"
|
||||
//#include "hk32f030m_awu.h"
|
||||
//#include "hk32f030m_beep.h"
|
||||
#include "hk32f030m_dbgmcu.h"
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
/* ########################## Assert Selection ############################## */
|
||||
/**
|
||||
* @brief Uncomment the line below to expanse the "assert_param" macro in the
|
||||
* drivers code
|
||||
*/
|
||||
|
||||
|
||||
//#define USE_FULL_ASSERT (1U)
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief The assert_param macro is used for function's parameters check.
|
||||
* @param expr: If expr is false, it calls assert_failed function
|
||||
* which reports the name of the source file and the source
|
||||
* line number of the call that failed.
|
||||
* If expr is true, it returns no value.
|
||||
* @retval None
|
||||
*/
|
||||
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((char *)__FILE__, __LINE__))
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void assert_failed(char* file, uint32_t line);
|
||||
#else
|
||||
#define assert_param(expr) ((void)0U)
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HK32F030M_CONF_H */
|
||||
|
||||
/************************ (C) COPYRIGHT MKMcircoChuip *****END OF FILE****/
|
||||
27
badge_firmware/code/inc/hk32f030m_it.h
Normal file
27
badge_firmware/code/inc/hk32f030m_it.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hk32f030m_it.h
|
||||
* @brief This file contains the headers of the interrupt handlers.
|
||||
******************************************************************************
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
#ifndef __HK32F030M_IT_H
|
||||
#define __HK32F030M_IT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Exported functions prototypes ---------------------------------------------*/
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void SVC_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HK32F030M_IT_H */
|
||||
105
badge_firmware/code/inc/hsv2rgb.h
Normal file
105
badge_firmware/code/inc/hsv2rgb.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* hsv2rgb.h
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_HSV2RGB_H_
|
||||
#define CODE_INC_HSV2RGB_H_
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef struct color_rgb {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
} color_rgb;
|
||||
|
||||
typedef struct color_hsv {
|
||||
uint16_t h;
|
||||
uint8_t s;
|
||||
uint8_t v;
|
||||
} color_hsv;
|
||||
|
||||
|
||||
#define HSV_HUE_SEXTANT 256
|
||||
#define HSV_HUE_STEPS (6 * HSV_HUE_SEXTANT)
|
||||
|
||||
#define HSV_HUE_MIN 0
|
||||
#define HSV_HUE_MAX (HSV_HUE_STEPS - 1)
|
||||
#define HSV_SAT_MIN 0
|
||||
#define HSV_SAT_MAX 255
|
||||
#define HSV_VAL_MIN 0
|
||||
#define HSV_VAL_MAX 255
|
||||
|
||||
/* Options: */
|
||||
#define HSV_USE_SEXTANT_TEST /* Limit the hue to 0...360 degrees */
|
||||
|
||||
|
||||
void hsv2rgb_8b(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g , uint8_t *b);
|
||||
|
||||
|
||||
/*
|
||||
* Macros that are common to all implementations
|
||||
*/
|
||||
#ifdef HSV_USE_SEXTANT_TEST
|
||||
#define HSV_SEXTANT_TEST(sextant) \
|
||||
if((sextant) > 5) { \
|
||||
(sextant) = 5; \
|
||||
}
|
||||
|
||||
#else
|
||||
#define HSV_SEXTANT_TEST(sextant)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Pointer swapping:
|
||||
* sext. r g b r<>b g<>b r <> g result
|
||||
* 0 0 0 v u c !u v c u v c
|
||||
* 0 0 1 d v c d v c
|
||||
* 0 1 0 c v u u v c u v c
|
||||
* 0 1 1 c d v v d c d v c d v c
|
||||
* 1 0 0 u c v u v c u v c
|
||||
* 1 0 1 v c d v d c d v c d v c
|
||||
*
|
||||
* if(sextant & 2)
|
||||
* r <-> b
|
||||
*
|
||||
* if(sextant & 4)
|
||||
* g <-> b
|
||||
*
|
||||
* if(!(sextant & 6) {
|
||||
* if(!(sextant & 1))
|
||||
* r <-> g
|
||||
* } else {
|
||||
* if(sextant & 1)
|
||||
* r <-> g
|
||||
* }
|
||||
*/
|
||||
#define HSV_SWAPPTR(a,b) do { uint8_t *tmp = (a); (a) = (b); (b) = tmp; } while(0)
|
||||
#define HSV_POINTER_SWAP(sextant,r,g,b) \
|
||||
do { \
|
||||
if((sextant) & 2) { \
|
||||
HSV_SWAPPTR((r), (b)); \
|
||||
} \
|
||||
if((sextant) & 4) { \
|
||||
HSV_SWAPPTR((g), (b)); \
|
||||
} \
|
||||
if(!((sextant) & 6)) { \
|
||||
if(!((sextant) & 1)) { \
|
||||
HSV_SWAPPTR((r), (g)); \
|
||||
} \
|
||||
} else { \
|
||||
if((sextant) & 1) { \
|
||||
HSV_SWAPPTR((r), (g)); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_HSV2RGB_H_ */
|
||||
17
badge_firmware/code/inc/i8atan2.h
Normal file
17
badge_firmware/code/inc/i8atan2.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* i8atan2.h
|
||||
*
|
||||
* Created on: Jul 18, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_I8ATAN2_H_
|
||||
#define CODE_INC_I8ATAN2_H_
|
||||
|
||||
|
||||
|
||||
int8_t i8atan2(int8_t y, int8_t x);
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_I8ATAN2_H_ */
|
||||
22
badge_firmware/code/inc/led_prog.h
Normal file
22
badge_firmware/code/inc/led_prog.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* led_prog.h
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_LED_PROG_H_
|
||||
#define CODE_INC_LED_PROG_H_
|
||||
|
||||
|
||||
|
||||
extern void (*ledprog)();
|
||||
|
||||
|
||||
|
||||
void ledprog_default();
|
||||
void ledprog_change();
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_LED_PROG_H_ */
|
||||
36
badge_firmware/code/inc/led_sk6x_spi.h
Normal file
36
badge_firmware/code/inc/led_sk6x_spi.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* led_sk6x_spi.h
|
||||
*
|
||||
* Created on: Jun 19, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_LED_SK6X_SPI_H_
|
||||
#define CODE_INC_LED_SK6X_SPI_H_
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SK6X_LED_MAX_COUNT 8
|
||||
|
||||
#define SK6X_BUF_SIZE (((SK6X_LED_MAX_COUNT * 24) * 5) / 8) // always a whole number
|
||||
|
||||
#define SK6X_HI 0x10 // 0b000_10000, or 0.25/1.00uS on/off
|
||||
#define SK6X_LO 0x1c // 0b000_11100, or 0.75/0.50uS on/off
|
||||
//#define SK6X_HI 0xc0 // 0b11000000, or 0.25/0.75uS on/off
|
||||
//#define SK6X_LO 0xfc // 0b11111100, or 0.75/0.25uS on/off
|
||||
|
||||
|
||||
|
||||
void led_sk6x_init();
|
||||
|
||||
void led_sk6x_set(uint8_t index, uint8_t r, uint8_t g, uint8_t b);
|
||||
void led_sk6x_set_all(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
void led_sk6x_process();
|
||||
void led_sk6x_update();
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_LED_SK6X_SPI_H_ */
|
||||
13
badge_firmware/code/inc/led_user.h
Normal file
13
badge_firmware/code/inc/led_user.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* led_user.h
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_LED_USER_H_
|
||||
#define CODE_INC_LED_USER_H_
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_LED_USER_H_ */
|
||||
37
badge_firmware/code/inc/prng.h
Normal file
37
badge_firmware/code/inc/prng.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* prng.h
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_PRNG_H_
|
||||
#define CODE_INC_PRNG_H_
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* tinymt32 internal state vector and parameters
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t status[4];
|
||||
uint32_t mat1;
|
||||
uint32_t mat2;
|
||||
uint32_t tmat;
|
||||
} tinymt32_t;
|
||||
|
||||
|
||||
|
||||
extern tinymt32_t tinymt32_s;
|
||||
|
||||
|
||||
|
||||
void tinymt32_init(tinymt32_t *s, uint32_t seed);
|
||||
uint32_t tinymt32_get_uint32(tinymt32_t* s);
|
||||
|
||||
#define prng_get8() (tinymt32_get_uint32(&tinymt32_s) & 0xff)
|
||||
#define prng_get16() (tinymt32_get_uint32(&tinymt32_s) & 0xffff)
|
||||
#define prng_get32() tinymt32_get_uint32(&tinymt32_s)
|
||||
|
||||
|
||||
#endif /* CODE_INC_PRNG_H_ */
|
||||
45
badge_firmware/code/inc/spi.h
Normal file
45
badge_firmware/code/inc/spi.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* spi.h
|
||||
*
|
||||
* Created on: Jun 19, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_SPI_H_
|
||||
#define CODE_INC_SPI_H_
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
#define SPI SPI1
|
||||
|
||||
#define SPI_MOSI_NONE 0
|
||||
|
||||
#define SPI_MOSI_SPI 1
|
||||
#define SPI_MOSI_SPI_PORT GPIOD
|
||||
#define SPI_MOSI_SPI_PIN 2
|
||||
#define SPI_MOSI_SPI_PINSRC GPIO_PinSource_2
|
||||
|
||||
#define SPI_CLK_PORT GPIOD
|
||||
#define SPI_CLK_PIN 3
|
||||
|
||||
#define SPI_MOSI_LED 2
|
||||
#define SPI_MOSI_LED_PORT GPIOD
|
||||
#define SPI_MOSI_LED_PIN 4
|
||||
#define SPI_MOSI_LED_PINSRC GPIO_PinSource_4
|
||||
|
||||
#define SPI_NO_CALLBACK (void (*)(void))(0x0)
|
||||
|
||||
|
||||
|
||||
void spi_init();
|
||||
void spi_xfer(uint8_t *tx, uint8_t *rx, uint16_t len, void (*cb)(void));
|
||||
|
||||
void spi_mosi_sel(uint8_t which);
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_SPI_H_ */
|
||||
17
badge_firmware/code/inc/timer.h
Normal file
17
badge_firmware/code/inc/timer.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* timer.h
|
||||
*
|
||||
* Created on: Jun 25, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef CODE_INC_TIMER_H_
|
||||
#define CODE_INC_TIMER_H_
|
||||
|
||||
|
||||
|
||||
void tim6_init();
|
||||
|
||||
|
||||
|
||||
#endif /* CODE_INC_TIMER_H_ */
|
||||
127
badge_firmware/code/src/adxl.c
Normal file
127
badge_firmware/code/src/adxl.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* adxl.c
|
||||
*
|
||||
* Created on: Jul 18, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
#include "adxl.h"
|
||||
#include "i8atan2.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
adxl345_axes adxl;
|
||||
adxl345_axes adxl_last[4];
|
||||
adxl345_axes adxl_smoothing;
|
||||
|
||||
uint8_t buf[7];
|
||||
|
||||
uint8_t last_idx = 0;
|
||||
int16_t movement = 0;
|
||||
uint16_t movement_worst = 0;
|
||||
|
||||
static const uint8_t adxl_dfmt = ADXL345_DATA_FORMAT_RANGE_2G; // | ADXL345_DATA_FORMAT_FULL_RES;
|
||||
|
||||
|
||||
|
||||
void adxl345_init()
|
||||
{
|
||||
buf[0] = ADXL345_REG_BW_RATE | ADXL345_MODE_WR | ADXL345_MODE_MB;
|
||||
buf[1] = ADXL345_BW_RATE_200; // | ADXL345_BW_RATE_LOW_POWER; // BW_RATE
|
||||
buf[2] = ADXL345_POWER_CTL_MEASURE; // POWER_CTL
|
||||
buf[3] = 0; // INT_ENABLE
|
||||
buf[4] = 0xff; // INT_MAP
|
||||
adxl_spi_xfer(0, buf, 5);
|
||||
|
||||
buf[0] = ADXL345_REG_DATA_FORMAT | ADXL345_MODE_WR;
|
||||
buf[1] = adxl_dfmt;
|
||||
adxl_spi_xfer(0, buf, 2);
|
||||
}
|
||||
|
||||
void adxl345_tick()
|
||||
{
|
||||
adxl_last[last_idx].x = adxl.x;
|
||||
adxl_last[last_idx].y = adxl.y;
|
||||
adxl_last[last_idx++].z = adxl.z;
|
||||
last_idx &= 0x3;
|
||||
|
||||
adxl345_get_axes(&adxl_smoothing);
|
||||
adxl.x += adxl_smoothing.x; adxl.x >>= 1;
|
||||
adxl.y += adxl_smoothing.y; adxl.y >>= 1;
|
||||
adxl.z += adxl_smoothing.z; adxl.z >>= 1;
|
||||
|
||||
if (!last_idx) {
|
||||
movement = 0;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
movement += (adxl_last[i].x - adxl.x) + (adxl_last[i].y - adxl.y) + (adxl_last[i].z - adxl.z);
|
||||
}
|
||||
if (abs(movement) > movement_worst) {
|
||||
movement_worst = abs(movement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adxl345_get_axes(struct adxl345_axes *adxl)
|
||||
{
|
||||
buf[0] = ADXL345_REG_DATAX0 | ADXL345_MODE_RD | ADXL345_MODE_MB;
|
||||
memset(&buf[1], 0x00, 6);
|
||||
adxl_spi_xfer(buf, buf, 7);
|
||||
|
||||
adxl->x = buf[1] | (buf[2] << 8);
|
||||
adxl->y = buf[3] | (buf[4] << 8);
|
||||
adxl->z = buf[5] | (buf[6] << 8);
|
||||
}
|
||||
|
||||
int8_t adxl345_get_rotation(struct adxl345_axes *adxl)
|
||||
{
|
||||
int8_t nx, ny, ret;
|
||||
|
||||
nx = -adxl->x;
|
||||
ny = adxl->y;
|
||||
|
||||
ret = i8atan2(nx, ny) >> 1;
|
||||
if (ret < 0) {
|
||||
ret += 128;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int16_t adxl345_movement()
|
||||
{
|
||||
return movement;
|
||||
}
|
||||
|
||||
void adxl345_set_reg8(uint8_t reg, uint8_t val)
|
||||
{
|
||||
buf[0] = reg | ADXL345_MODE_WR;
|
||||
buf[1] = val;
|
||||
adxl_spi_xfer(0, buf, 2);
|
||||
}
|
||||
|
||||
void adxl345_set_intr(uint8_t int2_map, uint8_t interrupt_flags)
|
||||
{
|
||||
buf[0] = ADXL345_REG_INT_ENABLE | ADXL345_MODE_WR | ADXL345_MODE_MB;
|
||||
buf[1] = interrupt_flags; // set interrupts which are enabled
|
||||
buf[2] = int2_map; // which interrupts map to INT2
|
||||
adxl_spi_xfer(0, buf, 3);
|
||||
}
|
||||
|
||||
void adxl345_set_intr_polarity(uint8_t active_polarity)
|
||||
{
|
||||
buf[0] = ADXL345_REG_DATA_FORMAT | ADXL345_MODE_WR;
|
||||
buf[1] = adxl_dfmt | (active_polarity ? 0 : ADXL345_DFMT_INT_INVERT);
|
||||
adxl_spi_xfer(buf, buf, 2);
|
||||
}
|
||||
|
||||
uint8_t adxl345_get_intr_flag()
|
||||
{
|
||||
buf[0] = ADXL345_REG_INT_SOURCE | ADXL345_MODE_RD;
|
||||
buf[1] = 0x00;
|
||||
adxl_spi_xfer(buf, buf, 2);
|
||||
|
||||
return buf[1];
|
||||
}
|
||||
108
badge_firmware/code/src/btn.c
Normal file
108
badge_firmware/code/src/btn.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* btn.c
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
static uint8_t mode = BTN_MODE_IDLE;
|
||||
|
||||
|
||||
#include "btn.h"
|
||||
|
||||
Btn_t btn[BTN_COUNT] = {0};
|
||||
|
||||
|
||||
|
||||
void btn_init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void btn_check(uint8_t idx, uint8_t state)
|
||||
{
|
||||
if (!state) { // buttons active low
|
||||
if (btn[idx].held < BTN_MAX_HOLD) {
|
||||
btn[idx].held++;
|
||||
}
|
||||
} else {
|
||||
btn[idx].held = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void btn_tick()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
// increment hold
|
||||
btn_check(0, BTN1);
|
||||
btn_check(1, BTN2);
|
||||
btn_check(2, BTN3);
|
||||
|
||||
// process
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
// test for hold / release, can only happen after push
|
||||
if ((btn[i].state & BTN_PUSH) || (btn[i].state & BTN_HELD)) {
|
||||
// release first
|
||||
if (btn[i].held == 0) {
|
||||
// yes, released
|
||||
btn[i].state = BTN_RELEASE;
|
||||
|
||||
// do we trigger hold?
|
||||
} else if (btn[i].hold_time && (btn[i].held >> BTN_HOLD_SHIFT) == btn[i].hold_time) {
|
||||
// yes, held, but only set if we didn't already
|
||||
if (!(btn[i].state & BTN_HELD)) {
|
||||
btn[i].state = BTN_HELD;
|
||||
btn[i].hold_rt_ctr = btn[i].hold_retrig;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// push
|
||||
if (btn[i].held == BTN_DEBOUNCE) {
|
||||
btn[i].state = BTN_PUSH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void btn_callback()
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t s;
|
||||
|
||||
for (i = 0; i < BTN_COUNT; i++) {
|
||||
s = btn[i].state;
|
||||
|
||||
if ((s & BTN_PUSH) && !(s & BTN_PUSH_CB)) {
|
||||
btn[i].state |= BTN_PUSH_CB;
|
||||
if (btn[i].push_cb) {
|
||||
btn[i].push_cb();
|
||||
}
|
||||
}
|
||||
|
||||
if (btn[i].hold_retrig) {
|
||||
if (btn[i].hold_rt_ctr) {
|
||||
btn[i].hold_rt_ctr--;
|
||||
} else {
|
||||
btn[i].hold_rt_ctr = btn[i].hold_retrig;
|
||||
btn[i].state &= ~(BTN_HELD_CB);
|
||||
}
|
||||
}
|
||||
|
||||
if ((s & BTN_HELD) && !(s & BTN_HELD_CB)) {
|
||||
btn[i].state |= BTN_HELD_CB;
|
||||
if (btn[i].held_cb) {
|
||||
btn[i].held_cb();
|
||||
}
|
||||
}
|
||||
|
||||
if ((s & BTN_RELEASE) && !(s & BTN_RELEASE_CB)) {
|
||||
btn[i].state |= BTN_RELEASE_CB;
|
||||
if (btn[i].release_cb) {
|
||||
btn[i].release_cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
141
badge_firmware/code/src/hk32f030m_it.c
Normal file
141
badge_firmware/code/src/hk32f030m_it.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file hk32f030m_it.c
|
||||
* @brief Interrupt Service Routines.
|
||||
******************************************************************************
|
||||
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "../../code/Inc/hk32f030m_it.h"
|
||||
|
||||
#include "hk32f030m_tim.h"
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN TD */
|
||||
|
||||
/* USER CODE END TD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PV */
|
||||
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
|
||||
/* USER CODE BEGIN EV */
|
||||
|
||||
/* USER CODE END EV */
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex-M0 Processor Interruption and Exception Handlers */
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* @brief This function handles Non maskable interrupt.
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||
|
||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||
|
||||
/* USER CODE END NonMaskableInt_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard fault interrupt.
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN HardFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END HardFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
||||
/* USER CODE END W1_HardFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System service call via SWI instruction.
|
||||
*/
|
||||
void SVC_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SVC_IRQn 0 */
|
||||
|
||||
/* USER CODE END SVC_IRQn 0 */
|
||||
/* USER CODE BEGIN SVC_IRQn 1 */
|
||||
|
||||
/* USER CODE END SVC_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pendable request for system service.
|
||||
*/
|
||||
void PendSV_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN PendSV_IRQn 0 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 0 */
|
||||
/* USER CODE BEGIN PendSV_IRQn 1 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System tick timer.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 1 */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* hk32f030m Peripheral Interrupt Handlers */
|
||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||
/* For the available peripheral interrupt handler names, */
|
||||
/* please refer to the startup file (startup_hk32f030m.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
//void TIM2_IRQHandler(void)
|
||||
//{
|
||||
// if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
|
||||
// {
|
||||
// TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
|
||||
// }
|
||||
//}
|
||||
/* USER CODE END 1 */
|
||||
/************************ (C) COPYRIGHT HKMicroChip *****END OF FILE****/
|
||||
94
badge_firmware/code/src/hsv2rgb.c
Normal file
94
badge_firmware/code/src/hsv2rgb.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 B. Stultiens
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "hsv2rgb.h"
|
||||
|
||||
|
||||
void hsv2rgb_8b(uint16_t h, uint8_t s, uint8_t v, uint8_t *r, uint8_t *g , uint8_t *b)
|
||||
{
|
||||
uint8_t sextant;
|
||||
uint8_t bb;
|
||||
uint16_t ww;
|
||||
uint8_t h_fraction;
|
||||
|
||||
if (!(s)) {
|
||||
*(r) = *(g) = *(b) = (v);
|
||||
return;
|
||||
}
|
||||
|
||||
sextant = h >> 8;
|
||||
HSV_SEXTANT_TEST(sextant); // Optional: Limit hue sextants to defined space
|
||||
|
||||
HSV_POINTER_SWAP(sextant, r, g, b); // Swap pointers depending which sextant we are in
|
||||
|
||||
*g = v; // Top level
|
||||
|
||||
// Perform actual calculations
|
||||
/*
|
||||
* Bottom level: v * (1.0 - s)
|
||||
* --> (v * (255 - s) + error_corr) / 256
|
||||
*/
|
||||
bb = ~s;
|
||||
ww = v * bb;
|
||||
ww += 1; // Error correction
|
||||
ww += ww >> 8; // Error correction
|
||||
*b = ww >> 8;
|
||||
|
||||
h_fraction = h & 0xff; // 0...255
|
||||
|
||||
if(!(sextant & 1)) {
|
||||
// *r = ...slope_up...;
|
||||
/*
|
||||
* Slope up: v * (1.0 - s * (1.0 - h))
|
||||
* --> (v * (255 - (s * (256 - h) + error_corr1) / 256) + error_corr2) / 256
|
||||
*/
|
||||
ww = !h_fraction ? ((uint16_t)s << 8) : (s * (uint8_t)(-h_fraction));
|
||||
ww += ww >> 8; // Error correction 1
|
||||
bb = ww >> 8;
|
||||
bb = ~bb;
|
||||
ww = v * bb;
|
||||
ww += v >> 1; // Error correction 2
|
||||
*r = ww >> 8;
|
||||
} else {
|
||||
// *r = ...slope_down...;
|
||||
/*
|
||||
* Slope down: v * (1.0 - s * h)
|
||||
* --> (v * (255 - (s * h + error_corr1) / 256) + error_corr2) / 256
|
||||
*/
|
||||
ww = s * h_fraction;
|
||||
ww += ww >> 8; // Error correction 1
|
||||
bb = ww >> 8;
|
||||
bb = ~bb;
|
||||
ww = v * bb;
|
||||
ww += v >> 1; // Error correction 2
|
||||
*r = ww >> 8;
|
||||
|
||||
/*
|
||||
* A perfect match for h_fraction == 0 implies:
|
||||
* *r = (ww >> 8) + (h_fraction ? 0 : 1)
|
||||
* However, this is an extra calculation that may not be required.
|
||||
*/
|
||||
}
|
||||
}
|
||||
51
badge_firmware/code/src/i8atan2.c
Normal file
51
badge_firmware/code/src/i8atan2.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* i8atan2.c
|
||||
*
|
||||
* Created on: Jul 18, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
static int8_t iat2(int8_t y, int8_t x)
|
||||
{
|
||||
return ((y * 32 + (x / 2)) / x) * 2;
|
||||
}
|
||||
|
||||
int8_t i8atan2(int8_t y, int8_t x)
|
||||
{
|
||||
// determine octant
|
||||
if (y >= 0) { // oct 0,1,2,3
|
||||
if (x >= 0) { // oct 0,1
|
||||
if (x > y) {
|
||||
return iat2(-y, -x) / 2 + (0 * 32);
|
||||
} else {
|
||||
if (y == 0) return 0; // (x=0,y=0)
|
||||
return -iat2(-x, -y) / 2 + (2 * 32);
|
||||
}
|
||||
} else { // oct 2,3
|
||||
if (x >= -y) {
|
||||
return iat2(x, -y) / 2 + (2 * 32);
|
||||
} else {
|
||||
return -iat2(-y, x) / 2 + (4 * 32);
|
||||
}
|
||||
}
|
||||
} else { // oct 4,5,6,7
|
||||
if (x < 0) { // oct 4,5
|
||||
if (x < y) {
|
||||
return iat2(y, x) / 2 + (-4 * 32);
|
||||
} else {
|
||||
return -iat2(x, y) / 2 + (-2 * 32);
|
||||
}
|
||||
} else { // oct 6,7
|
||||
if (-x >= y) {
|
||||
return iat2(-x, y) / 2 + (-2 * 32);
|
||||
} else {
|
||||
return -iat2(y, -x) / 2 + (-0 * 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
296
badge_firmware/code/src/led_prog.c
Normal file
296
badge_firmware/code/src/led_prog.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* led_prog.c
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hsv2rgb.h"
|
||||
#include "led_sk6x_spi.h"
|
||||
#include "prng.h"
|
||||
|
||||
|
||||
|
||||
void ledprog0_twinkle_white();
|
||||
void ledprog1_twinkle_rgb_rand();
|
||||
void ledprog2_twinkle_rgb_set();
|
||||
void ledprog3_rainbow();
|
||||
void ledprog4_flicker_same();
|
||||
void ledprog5_flicker_all();
|
||||
void ledprog6_ramper();
|
||||
|
||||
|
||||
static uint8_t settings[16][4];
|
||||
|
||||
const void (*led_prog_list[])() = {
|
||||
ledprog0_twinkle_white,
|
||||
ledprog1_twinkle_rgb_rand,
|
||||
ledprog2_twinkle_rgb_set,
|
||||
ledprog3_rainbow,
|
||||
ledprog4_flicker_same,
|
||||
ledprog5_flicker_all,
|
||||
ledprog6_ramper
|
||||
};
|
||||
|
||||
void (*ledprog)();
|
||||
static uint32_t work[4];
|
||||
|
||||
static uint8_t r, g, b;
|
||||
|
||||
|
||||
|
||||
void ledprog_default()
|
||||
{
|
||||
settings[3][2] = 2;
|
||||
settings[3][3] = 30;
|
||||
|
||||
settings[4][1] = 248;
|
||||
settings[4][2] = 170;
|
||||
settings[4][3] = 16;
|
||||
|
||||
settings[6][1] = 192;
|
||||
settings[6][2] = 30;
|
||||
settings[6][3] = 6;
|
||||
}
|
||||
|
||||
void ledprog_change(uint8_t idx)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
ledprog = led_prog_list[idx];
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
work[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
uint8_t x;
|
||||
|
||||
x = prng_get8();
|
||||
|
||||
led_sk6x_set_all(0, 0, 0);
|
||||
|
||||
if (x > 240) {
|
||||
x = prng_get32() & 0x7;
|
||||
led_sk6x_set(x, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* settings:
|
||||
* 0 dwell
|
||||
* 1 threshold
|
||||
*/
|
||||
void ledprog0_twinkle_white()
|
||||
{
|
||||
ledprogi_twinkle(0xff, 0xff, 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* settings:
|
||||
* 0 dwell
|
||||
* 1 threshold
|
||||
*/
|
||||
void ledprog1_twinkle_rgb_rand()
|
||||
{
|
||||
uint32_t x;
|
||||
|
||||
x = prng_get32();
|
||||
|
||||
// set values
|
||||
r = (x >> 24);
|
||||
g = (x >> 16) & 0xff;
|
||||
b = (x >> 8) & 0xff;
|
||||
|
||||
// randomly reduce colors to remove "whiteness"
|
||||
switch (x & 0x3) {
|
||||
case 1: {
|
||||
r >>= 4;
|
||||
g >>= 4;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
g >>= 4;
|
||||
b >>= 4;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
b >>= 4;
|
||||
r >>= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ledprogi_twinkle(r, g, b);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* settings:
|
||||
* 0 dwell
|
||||
* 1 threshold
|
||||
* 2 hue
|
||||
* 3 val
|
||||
*/
|
||||
void ledprog2_twinkle_rgb_set()
|
||||
{
|
||||
hsv2rgb_8b(settings[2][2] * 6, 255, settings[2][3], &r, &g, &b);
|
||||
|
||||
ledprogi_twinkle(r, g, b);
|
||||
}
|
||||
|
||||
/*
|
||||
* settings:
|
||||
* 0 dwell
|
||||
* 1 threshold
|
||||
* 2 speed
|
||||
* 3 skip
|
||||
*
|
||||
* work:
|
||||
* 0 base hue
|
||||
*/
|
||||
void ledprog3_rainbow()
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t w;
|
||||
|
||||
work[0] += (settings[3][2] * 6) + 1;
|
||||
work[0] %= 1536;
|
||||
w = work[0];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
hsv2rgb_8b(w, 255, 255, &r, &g, &b);
|
||||
led_sk6x_set(i, r, g, b);
|
||||
|
||||
w += (settings[3][3] * 6) + 1;
|
||||
w %= 1536;
|
||||
}
|
||||
}
|
||||
|
||||
void ledprogi_flicker()
|
||||
{
|
||||
uint16_t h;
|
||||
uint8_t x;
|
||||
|
||||
h = settings[4][2] * 6;
|
||||
|
||||
x = prng_get8();
|
||||
|
||||
if (x > settings[4][1]) {
|
||||
x = 255;
|
||||
} else {
|
||||
x = settings[4][3];
|
||||
}
|
||||
|
||||
x &= ~0x07;
|
||||
x |= prng_get32() & 0x07;
|
||||
|
||||
hsv2rgb_8b(h, 255, x, &r, &g, &b);
|
||||
}
|
||||
|
||||
/*
|
||||
* settings:
|
||||
* 0 dwell
|
||||
* 1 threshold
|
||||
* 2 hue
|
||||
* 3 base
|
||||
*/
|
||||
void ledprog4_flicker_same()
|
||||
{
|
||||
ledprogi_flicker();
|
||||
led_sk6x_set_all(r, g, b);
|
||||
}
|
||||
|
||||
/*
|
||||
* settings (uses ledprog4)
|
||||
* 0 dwell
|
||||
* 1 threshold
|
||||
* 2 hue
|
||||
* 3 val
|
||||
*/
|
||||
void ledprog5_flicker_all()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
ledprogi_flicker();
|
||||
led_sk6x_set(i, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* settings
|
||||
* 0 dwell
|
||||
* 1 speed
|
||||
* 2 hue
|
||||
* 3 faderate
|
||||
*
|
||||
* work:
|
||||
* 0 ramper state
|
||||
*/
|
||||
void ledprog6_ramper()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
uint16_t h;
|
||||
int16_t spd;
|
||||
|
||||
uint16_t floor = 0;
|
||||
uint8_t v[8];
|
||||
uint8_t fr;
|
||||
|
||||
|
||||
h = settings[6][2] * 6;
|
||||
fr = settings[6][3] & 0x3f;
|
||||
|
||||
// speed -64 to -1, +1 to +64
|
||||
spd = (settings[6][1] >> 1) - 64;
|
||||
if (spd >= 0) spd++;
|
||||
work[0] += spd;
|
||||
work[0] &= 0xfff;
|
||||
|
||||
// unpack fade values
|
||||
for (i = 0; i < 4; i++) {
|
||||
v[0 + i] = work[2] >> (i * 8);
|
||||
v[4 + i] = work[3] >> (i * 8);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
// set to max if within range
|
||||
if (work[0] >= floor && work[0] <= floor + 64) {
|
||||
v[i] = 255;
|
||||
}
|
||||
|
||||
// set LED
|
||||
hsv2rgb_8b(h, 255, v[i], &r, &g, &b);
|
||||
led_sk6x_set(i, r, g, b);
|
||||
|
||||
// set fadeout value
|
||||
if (fr > v[i]) {
|
||||
v[i] = 0;
|
||||
} else {
|
||||
v[i] -= fr;
|
||||
}
|
||||
|
||||
// both sides of top LEDs match
|
||||
if (i == 5) {
|
||||
i++;
|
||||
led_sk6x_set(i, r, g, b);
|
||||
}
|
||||
|
||||
// work up the chain
|
||||
floor += 0x180;
|
||||
}
|
||||
|
||||
// pack fade values
|
||||
work[2] = work[3] = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
work[2] |= v[0 + i] << (i * 8);
|
||||
work[3] |= v[4 + i] << (i * 8);
|
||||
}
|
||||
}
|
||||
146
badge_firmware/code/src/led_sk6x_spi.c
Normal file
146
badge_firmware/code/src/led_sk6x_spi.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* led_sk6x_spi.c
|
||||
*
|
||||
* Created on: Jun 19, 2023
|
||||
* Author: true
|
||||
*
|
||||
* communicates with SK68xx LEDs using the SPI peripheral.
|
||||
*
|
||||
* this code operates the SPI at 4MHz and uses 5 bits to represent
|
||||
* each on-wire bit, resulting in 800KHz data rate.
|
||||
*
|
||||
* originally,
|
||||
* for the working buffer, each 5-bit word is stored in an 8-bit byte.
|
||||
* so, one byte per on-wire bit will be used. for RGB LEDs, 24 bits
|
||||
* per LED are required, so working memory use will be 24*LED_COUNT bytes.
|
||||
* the spi peripheral will only transfer the lower 5 bits of each byte.
|
||||
*
|
||||
* however,
|
||||
* this MCU supports 5-bit SPI mode, but has no DMA and isn't fast enough
|
||||
* to maintain continuous transfer at this rate. instead of trying to make
|
||||
* this work, we'll instead waste time and memory with a separate output
|
||||
* buffer. data will be generated for the output buffer from a separate
|
||||
* LEDvalue buffer by bit manipulating values into it.
|
||||
*
|
||||
* another note:
|
||||
* this would likely work perfectly fine with the weird delays between bits.
|
||||
* I was focused on making a very nice looking output waveform. I may test
|
||||
* and address this after con to reduce battery life, but considering the
|
||||
* draw of the LEDs and any addons, a worst case extra 1mA or so isn't shit.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "led_sk6x_spi.h"
|
||||
#include "spi.h"
|
||||
|
||||
#include "adxl.h"
|
||||
|
||||
|
||||
|
||||
#define SK6X_FILL(COLOR) \
|
||||
for (uint8_t mask = 0x80; mask; mask >>= 1) { \
|
||||
if (COLOR & mask) { \
|
||||
*p++ = SK6X_LO; \
|
||||
} else { \
|
||||
*p++ = SK6X_HI; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
const uint8_t sk6x_map[8] = {0, 1, 2, 3, 4, 7, 6, 5};
|
||||
|
||||
uint8_t sk6x_led[SK6X_LED_MAX_COUNT][3]; // G-R-B order
|
||||
uint8_t sk6x_buf[SK6X_BUF_SIZE];
|
||||
|
||||
uint8_t sk6x_brightness = 3;
|
||||
|
||||
|
||||
|
||||
void led_sk6x_cb();
|
||||
|
||||
|
||||
|
||||
void led_sk6x_init()
|
||||
{
|
||||
// configure ADXL to enable power
|
||||
adxl345_set_intr_polarity(ADXL345_INTR_ACTIVE_LO);
|
||||
|
||||
// clear led buffers
|
||||
memset(sk6x_led, 0, sizeof(sk6x_led));
|
||||
memset(sk6x_buf, 0, sizeof(sk6x_buf));
|
||||
}
|
||||
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_process()
|
||||
{
|
||||
uint8_t i, j;
|
||||
uint16_t n = 0;
|
||||
uint8_t b[8];
|
||||
|
||||
j = 0;
|
||||
|
||||
// pack RGB values into 5-bits-per-bit format
|
||||
for (i = 0; i < SK6X_LED_MAX_COUNT; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
// pack values for next color
|
||||
uint8_t *p = b;
|
||||
SK6X_FILL(sk6x_led[sk6x_map[i]][j] >> sk6x_brightness);
|
||||
|
||||
// pack 8 bits into 5 bytes in final buffer
|
||||
sk6x_buf[n + 0] = (b[0] << 3) | (b[1] >> 2);
|
||||
sk6x_buf[n + 1] = (b[1] << 6) | (b[2] << 1) | (b[3] >> 4);
|
||||
sk6x_buf[n + 2] = (b[3] << 4) | (b[4] >> 1);
|
||||
sk6x_buf[n + 3] = (b[4] << 7) | (b[5] << 2) | (b[6] >> 3);
|
||||
sk6x_buf[n + 4] = (b[6] << 5) | (b[7]);
|
||||
n += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_update()
|
||||
{
|
||||
// configure MOSI pin and bit depth
|
||||
spi_mosi_sel(SPI_MOSI_LED);
|
||||
|
||||
// begin sending data
|
||||
spi_xfer(sk6x_buf, 0, sizeof(sk6x_buf), SPI_NO_CALLBACK);
|
||||
}
|
||||
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_set(uint8_t index, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
/*
|
||||
uint8_t *p = &sk6x_buf[24 * index];
|
||||
SK6X_FILL(g);
|
||||
SK6X_FILL(r);
|
||||
SK6X_FILL(b);
|
||||
*/
|
||||
sk6x_led[index][0] = g;
|
||||
sk6x_led[index][1] = r;
|
||||
sk6x_led[index][2] = b;
|
||||
}
|
||||
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_set_all(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
/*
|
||||
uint8_t *p = sk6x_buf;
|
||||
for (uint8_t i = 0; i < SK6X_LED_MAX_COUNT; i++) {
|
||||
SK6X_FILL(g);
|
||||
SK6X_FILL(r);
|
||||
SK6X_FILL(b);
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < SK6X_LED_MAX_COUNT; i++) {
|
||||
led_sk6x_set(i, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void led_sk6x_cb()
|
||||
{
|
||||
// there is nothing to handle after updating LEDs
|
||||
}
|
||||
8
badge_firmware/code/src/led_user.c
Normal file
8
badge_firmware/code/src/led_user.c
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* led_user.c
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
280
badge_firmware/code/src/main.c
Normal file
280
badge_firmware/code/src/main.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* main.c.c
|
||||
*
|
||||
* Created on: Jun 19, 2023
|
||||
* Author: true
|
||||
*
|
||||
* HK32F030MF4P6 MCU running at 32MHz
|
||||
* (wanted to run slower, but want perfect waveform using SPI for LED)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "hk32f030m.h"
|
||||
|
||||
#include "adxl.h"
|
||||
#include "btn.h"
|
||||
#include "led_prog.h"
|
||||
#include "led_sk6x_spi.h"
|
||||
#include "prng.h"
|
||||
#include "spi.h"
|
||||
#include "timer.h"
|
||||
|
||||
|
||||
|
||||
#define GPIO_RCC_AHB_GPIO_ALL RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | \
|
||||
RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD
|
||||
|
||||
|
||||
|
||||
static uint32_t uptime = 0; // uptime in seconds
|
||||
volatile uint16_t cnt = 0; // 1/1000 second tick
|
||||
static uint16_t cnt2 = 0; // low priority loop check
|
||||
|
||||
|
||||
|
||||
static void gpio_init()
|
||||
{
|
||||
GPIO_InitTypeDef gpio;
|
||||
|
||||
// enable clocks
|
||||
RCC_AHBPeriphClockCmd(GPIO_RCC_AHB_GPIO_ALL, ENABLE);
|
||||
|
||||
// I2C AF config
|
||||
GPIOB->AFR[0] = 0x00010000; // _, _, _, USART RX, _, _, _, _
|
||||
GPIOC->AFR[0] = 0x20000000; // SPI MISO, I2C SCL, I2C SDA, _, _, _, _, _
|
||||
GPIOD->AFR[0] = 0x00022210; // _, _, _, LED MOSI, SPI SCK, SPI MOSI, USART TX, _
|
||||
|
||||
/*
|
||||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_0); // I2C SDA
|
||||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_0); // I2C SCL
|
||||
|
||||
// UART AF config
|
||||
GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_1); // USART RX
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_1); // USART TX
|
||||
|
||||
// SPI AF config
|
||||
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_2); // SPI MISO
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_2); // SPI MOSI
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_2); // SPI Clock
|
||||
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_2); // LED MOSI
|
||||
*/
|
||||
|
||||
// output pins, including defaults for AF pins
|
||||
gpio.GPIO_Mode = GPIO_Mode_OUT;
|
||||
gpio.GPIO_Speed = GPIO_Speed_2MHz;
|
||||
gpio.GPIO_OType = GPIO_OType_PP;
|
||||
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
gpio.GPIO_Schmit = GPIO_Schmit_Enable;
|
||||
|
||||
// ADXL !SS
|
||||
GPIOC->ODR = GPIO_Pin_4;
|
||||
gpio.GPIO_Pin = GPIO_Pin_4;
|
||||
GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// User LED
|
||||
GPIOD->ODR = GPIO_Pin_7;
|
||||
gpio.GPIO_Pin = GPIO_Pin_7;
|
||||
GPIO_Init(GPIOD, &gpio);
|
||||
|
||||
// for now, float I2C pins
|
||||
gpio.GPIO_OType = GPIO_OType_OD;
|
||||
gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
|
||||
GPIOC->ODR = GPIO_Pin_5 | GPIO_Pin_6;
|
||||
GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// SPI MOSI, LED MOSI
|
||||
// SPI MOSI will always idle low
|
||||
// LED MOSI will idle high when in standby, otherwise idle low
|
||||
gpio.GPIO_Speed = GPIO_Speed_10MHz;
|
||||
gpio.GPIO_OType = GPIO_OType_PP;
|
||||
gpio.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_4;
|
||||
GPIOD->ODR = GPIO_Pin_3 | GPIO_Pin_4;
|
||||
GPIO_Init(GPIOD, &gpio);
|
||||
|
||||
|
||||
|
||||
// --digital input pins--
|
||||
gpio.GPIO_Mode = GPIO_Mode_IN;
|
||||
|
||||
// ADXL_INT
|
||||
gpio.GPIO_Pin = GPIO_Pin_3;
|
||||
GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// BTN0-BTN2
|
||||
gpio.GPIO_PuPd = GPIO_PuPd_UP;
|
||||
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
|
||||
GPIO_Init(GPIOA, &gpio);
|
||||
|
||||
|
||||
|
||||
// --analog input pins--
|
||||
gpio.GPIO_Mode = GPIO_Mode_AN;
|
||||
|
||||
// VBAT
|
||||
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
||||
gpio.GPIO_Pin = GPIO_Pin_6;
|
||||
GPIO_Init(GPIOD, &gpio);
|
||||
|
||||
|
||||
|
||||
// --alternate function pins--
|
||||
gpio.GPIO_Mode = GPIO_Mode_AF;
|
||||
|
||||
// I2C SDA, I2C SCL
|
||||
//gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
|
||||
//GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// SPI MISO
|
||||
gpio.GPIO_Pin = GPIO_Pin_7;
|
||||
GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// USART TX, SPI SCK
|
||||
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3;
|
||||
GPIO_Init(GPIOD, &gpio);
|
||||
|
||||
// USART RX
|
||||
gpio.GPIO_PuPd = GPIO_PuPd_DOWN;
|
||||
gpio.GPIO_Pin = GPIO_Pin_4;
|
||||
GPIO_Init(GPIOB, &gpio);
|
||||
}
|
||||
|
||||
// startup
|
||||
int main(void)
|
||||
{
|
||||
// configure system IO
|
||||
gpio_init();
|
||||
|
||||
// configure SPI and peripheral
|
||||
spi_init();
|
||||
adxl345_init();
|
||||
adxl345_tick();
|
||||
|
||||
// configure prng
|
||||
tinymt32_init(&tinymt32_s, (adxl.x << 16) | (adxl.y << 8) | adxl.z);
|
||||
|
||||
// configure addressable LEDs
|
||||
led_sk6x_init();
|
||||
|
||||
ledprog_default();
|
||||
ledprog_change(6);
|
||||
|
||||
// configure user input
|
||||
btn_init();
|
||||
|
||||
// configure mainline timer
|
||||
#ifdef DEBUG
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_DBGMCU, ENABLE);
|
||||
DBGMCU->CR = DBGMCU_CR_DBG_STOP; // enable debug while in STOP (low power debug)
|
||||
DBGMCU->APB1FZ |= DBGMCU_TIM6_STOP; // stop timer while debugging
|
||||
#endif
|
||||
tim6_init();
|
||||
|
||||
// do nothing
|
||||
while(1) {
|
||||
if (cnt2 != cnt) {
|
||||
cnt2++;
|
||||
if (cnt2 >= 1024) cnt2 = 0;
|
||||
|
||||
// button processing (512Hz)
|
||||
if (cnt2 & 1) {
|
||||
btn_callback();
|
||||
}
|
||||
|
||||
// led programs (128Hz)
|
||||
if ((cnt2 & 0x7) == 0) {
|
||||
if (ledprog) ledprog();
|
||||
|
||||
// stuff next LED bits
|
||||
led_sk6x_process();
|
||||
}
|
||||
}
|
||||
|
||||
__WFI();
|
||||
}
|
||||
}
|
||||
|
||||
// main code loop
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler()
|
||||
{
|
||||
// clear interrupt
|
||||
TIM6->SR = 0;
|
||||
|
||||
// attempt sending LEDs
|
||||
if ((cnt & 0x7) == 0) {
|
||||
led_sk6x_update();
|
||||
}
|
||||
|
||||
// read buttons
|
||||
if (cnt & 1) {
|
||||
btn_tick();
|
||||
}
|
||||
|
||||
// temp: run LED program
|
||||
/*
|
||||
static uint8_t v[3];
|
||||
static uint8_t x = 0;
|
||||
if (!(cnt % 4)) {
|
||||
v[x]++;
|
||||
if (!v[x]) {
|
||||
x++;
|
||||
if (x >= 3) x = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// run next LED program
|
||||
|
||||
/*
|
||||
uint8_t w[2];
|
||||
w[0] = v[0] >> 2;
|
||||
w[1] = v[1] >> 2;
|
||||
w[2] = v[2] >> 2;
|
||||
led_sk6x_set(0, w[0], w[1], w[2]);
|
||||
led_sk6x_set(1, w[1], w[2], w[0]);
|
||||
led_sk6x_set(2, w[2], w[0], w[1]);
|
||||
led_sk6x_set(3, w[1], w[2], w[0]);
|
||||
led_sk6x_set(4, w[0], w[1], w[2]);
|
||||
led_sk6x_set(5, w[0], w[1], w[2]);
|
||||
led_sk6x_set(6, w[1], w[2], w[0]);
|
||||
led_sk6x_set(7, w[2], w[0], w[1]);
|
||||
*/
|
||||
/*
|
||||
for (int i = 1; i < 8; i++) {
|
||||
led_sk6x_set(i, v[0] + (i * 32), v[1] + (i * 32), v[2] + (i * 32));
|
||||
}
|
||||
*/
|
||||
|
||||
// accelerometer: tick
|
||||
if ((cnt & 0x3f) == 0x3f) {
|
||||
adxl345_tick();
|
||||
}
|
||||
|
||||
|
||||
// timing
|
||||
cnt++;
|
||||
if (cnt >= 1024) {
|
||||
cnt = 0;
|
||||
uptime++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @retval None
|
||||
*/
|
||||
void assert_failed(char* file , uint32_t line)
|
||||
{
|
||||
/* User can add his own implementation to report the file name and line number,
|
||||
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
|
||||
/* Infinite loop */
|
||||
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif /* USE_FULL_ASSERT */
|
||||
158
badge_firmware/code/src/prng.c
Normal file
158
badge_firmware/code/src/prng.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* prng.c
|
||||
*
|
||||
* Created on: Aug 3, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Tiny Mersenne Twister: only 127-bit internal state.
|
||||
* Derived from the reference implementation version 1.1 (2015/04/24)
|
||||
* by Mutsuo Saito (Hiroshima University) and Makoto Matsumoto
|
||||
* (Hiroshima University).
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "prng.h"
|
||||
|
||||
|
||||
|
||||
static void tinymt32_next_state(tinymt32_t *s);
|
||||
static uint32_t tinymt32_temper(tinymt32_t *s);
|
||||
|
||||
|
||||
|
||||
tinymt32_t tinymt32_s;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parameter set to use for this IETF specification. Don't change.
|
||||
* This parameter set is the first entry of the precalculated
|
||||
* parameter sets in tinymt32dc/tinymt32dc.0.1048576.txt by
|
||||
* Kenji Rikitake, available at:
|
||||
* https://github.com/jj1bdx/tinymtdc-longbatch/.
|
||||
* It is also the parameter set used in:
|
||||
* Rikitake, K., "TinyMT pseudo random number generator for
|
||||
* Erlang", Proceedings of the 11th ACM SIGPLAN Erlang Workshop,
|
||||
* September 2012.
|
||||
*/
|
||||
const uint32_t TINYMT32_MAT1_PARAM = UINT32_C(0x8f7011ee);
|
||||
const uint32_t TINYMT32_MAT2_PARAM = UINT32_C(0xfc78ff1f);
|
||||
const uint32_t TINYMT32_TMAT_PARAM = UINT32_C(0x3793fdff);
|
||||
|
||||
/**
|
||||
* This function initializes the internal state array with a
|
||||
* 32-bit unsigned integer seed.
|
||||
* @param s pointer to tinymt internal state.
|
||||
* @param seed a 32-bit unsigned integer used as a seed.
|
||||
*/
|
||||
void tinymt32_init (tinymt32_t* s, uint32_t seed)
|
||||
{
|
||||
const uint32_t MIN_LOOP = 8;
|
||||
const uint32_t PRE_LOOP = 8;
|
||||
s->status[0] = seed;
|
||||
s->status[1] = s->mat1 = TINYMT32_MAT1_PARAM;
|
||||
s->status[2] = s->mat2 = TINYMT32_MAT2_PARAM;
|
||||
s->status[3] = s->tmat = TINYMT32_TMAT_PARAM;
|
||||
for (int i = 1; i < MIN_LOOP; i++) {
|
||||
s->status[i & 3] ^= i + UINT32_C(1812433253)
|
||||
* (s->status[(i - 1) & 3]
|
||||
^ (s->status[(i - 1) & 3] >> 30));
|
||||
}
|
||||
/*
|
||||
* NB: The parameter set of this specification warrants
|
||||
* that none of the possible 2^^32 seeds leads to an
|
||||
* all-zero 127-bit internal state. Therefore, the
|
||||
* period_certification() function of the original
|
||||
* TinyMT32 source code has been safely removed. If
|
||||
* another parameter set is used, this function will
|
||||
* have to be reintroduced here.
|
||||
*/
|
||||
for (int i = 0; i < PRE_LOOP; i++) {
|
||||
tinymt32_next_state(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function outputs a 32-bit unsigned integer from
|
||||
* the internal state.
|
||||
* @param s pointer to tinymt internal state.
|
||||
* @return 32-bit unsigned integer r (0 <= r < 2^32).
|
||||
*/
|
||||
uint32_t tinymt32_get_uint32(tinymt32_t* s)
|
||||
{
|
||||
tinymt32_next_state(s);
|
||||
return tinymt32_temper(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal tinymt32 constants and functions.
|
||||
* Users should not call these functions directly.
|
||||
*/
|
||||
const uint32_t TINYMT32_SH0 = 1;
|
||||
const uint32_t TINYMT32_SH1 = 10;
|
||||
const uint32_t TINYMT32_SH8 = 8;
|
||||
const uint32_t TINYMT32_MASK = UINT32_C(0x7fffffff);
|
||||
|
||||
/**
|
||||
* This function changes the internal state of tinymt32.
|
||||
* @param s pointer to tinymt internal state.
|
||||
*/
|
||||
static void tinymt32_next_state (tinymt32_t* s)
|
||||
{
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
|
||||
y = s->status[3];
|
||||
x = (s->status[0] & TINYMT32_MASK)
|
||||
^ s->status[1]
|
||||
^ s->status[2];
|
||||
x ^= (x << TINYMT32_SH0);
|
||||
y ^= (y >> TINYMT32_SH0) ^ x;
|
||||
s->status[0] = s->status[1];
|
||||
s->status[1] = s->status[2];
|
||||
s->status[2] = x ^ (y << TINYMT32_SH1);
|
||||
s->status[3] = y;
|
||||
/*
|
||||
* The if (y & 1) {...} block below replaces:
|
||||
* s->status[1] ^= -((int32_t)(y & 1)) & s->mat1;
|
||||
* s->status[2] ^= -((int32_t)(y & 1)) & s->mat2;
|
||||
* The adopted code is equivalent to the original code
|
||||
* but does not depend on the representation of negative
|
||||
* integers by 2's complements. It is therefore more
|
||||
* portable but includes an if branch, which may slow
|
||||
* down the generation speed.
|
||||
*/
|
||||
if (y & 1) {
|
||||
s->status[1] ^= s->mat1;
|
||||
s->status[2] ^= s->mat2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function outputs a 32-bit unsigned integer from
|
||||
* the internal state.
|
||||
* @param s pointer to tinymt internal state.
|
||||
* @return 32-bit unsigned pseudorandom number.
|
||||
*/
|
||||
static uint32_t tinymt32_temper (tinymt32_t* s)
|
||||
{
|
||||
uint32_t t0, t1;
|
||||
t0 = s->status[3];
|
||||
t1 = s->status[0] + (s->status[2] >> TINYMT32_SH8);
|
||||
t0 ^= t1;
|
||||
/*
|
||||
* The if (t1 & 1) {...} block below replaces:
|
||||
* t0 ^= -((int32_t)(t1 & 1)) & s->tmat;
|
||||
* The adopted code is equivalent to the original code
|
||||
* but does not depend on the representation of negative
|
||||
* integers by 2's complements. It is therefore more
|
||||
* portable but includes an if branch, which may slow
|
||||
* down the generation speed.
|
||||
*/
|
||||
if (t1 & 1) {
|
||||
t0 ^= s->tmat;
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
228
badge_firmware/code/src/spi.c
Normal file
228
badge_firmware/code/src/spi.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* spi.c
|
||||
*
|
||||
* Created on: Jun 19, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
#include "hk32f030m.h"
|
||||
#include "spi.h"
|
||||
|
||||
|
||||
|
||||
uint8_t *spi_txbuf;
|
||||
uint8_t *spi_rxbuf;
|
||||
uint16_t spi_xfer_len;
|
||||
|
||||
uint16_t spi_txpos;
|
||||
uint16_t spi_rxpos;
|
||||
|
||||
void (*spi_done_cb)(void);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* sets up SPI peripheral.
|
||||
*/
|
||||
void spi_init()
|
||||
{
|
||||
// NVIC_InitTypeDef nvic;
|
||||
|
||||
// enable SPI clock
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
|
||||
|
||||
// run at 4MHz, master mode 3
|
||||
SPI->CR1 = SPI_BaudRatePrescaler_8 | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA;
|
||||
// default to 8-bit, interrupts disabled, motorola mode
|
||||
SPI->CR2 = SPI_CR2_FRXTH | SPI_DataSize_8b;
|
||||
|
||||
/*
|
||||
* originally I wanted to use interrupts, but it ended up being WAY too slow.
|
||||
* all of our transfers are pretty quick anyway, so using the hardware peripheral
|
||||
* just to make sure timings are good. we aren't wasting too much energy I guess...
|
||||
*
|
||||
// configure and enable IRQ
|
||||
nvic.NVIC_IRQChannel = SPI1_IRQn;
|
||||
nvic.NVIC_IRQChannelPriority = 0;
|
||||
nvic.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic);
|
||||
*/
|
||||
|
||||
// enable SPI
|
||||
SPI->CR1 |= SPI_CR1_SPE;
|
||||
}
|
||||
|
||||
/*
|
||||
* starts an SPI transfer. assumes you have set slave select before calling.
|
||||
* all transfers are BLOCKING.
|
||||
* if callback is set to a function, will be executed when xfer is done.
|
||||
*/
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void spi_xfer(uint8_t *tx, uint8_t *rx, uint16_t len, void (*cb)(void))
|
||||
{
|
||||
uint16_t flags;
|
||||
uint16_t val;
|
||||
uint8_t txb = 0;
|
||||
uint8_t rxb = 0;
|
||||
|
||||
volatile uint8_t *spi_dr = (volatile uint8_t *)((uint32_t)SPI + 0x0c);
|
||||
|
||||
// wait until the SPI is not busy
|
||||
while (SPI->SR & SPI_SR_BSY);
|
||||
|
||||
// transfer all of our data
|
||||
while (txb != len) {
|
||||
flags = SPI->SR;
|
||||
|
||||
// load next byte to send
|
||||
val = tx ? tx[txb] : 0;
|
||||
|
||||
// transmit FIFO has space? if so, send byte
|
||||
if ((flags & SPI_SR_FTLVL) != SPI_SR_FTLVL) {
|
||||
*spi_dr = val;
|
||||
txb++;
|
||||
}
|
||||
|
||||
// receive FIFO has data for us? if so, receive byte
|
||||
if (flags & SPI_SR_RXNE) {
|
||||
val = *spi_dr;
|
||||
if (rx) rx[rxb] = val;
|
||||
rxb++;
|
||||
}
|
||||
}
|
||||
|
||||
// we shouldn't hit this code, but if there are bytes left over in FIFO...
|
||||
while (rxb != len) {
|
||||
flags = SPI->SR;
|
||||
|
||||
// receive FIFO has data for us? if so, receive byte
|
||||
if (flags & SPI_SR_RXNE) {
|
||||
val = *spi_dr;
|
||||
if (rx) rx[rxb] = val;
|
||||
rxb++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// load first byte to send
|
||||
val = tx ? tx[0] : 0;
|
||||
// and send it
|
||||
SPI_SendData8(SPI, tx[0]);
|
||||
|
||||
// set values for this transfer
|
||||
spi_txbuf = tx;
|
||||
spi_rxbuf = rx;
|
||||
spi_xfer_len = len;
|
||||
spi_done_cb = cb;
|
||||
// set initial buffer positions
|
||||
spi_txpos = 1;
|
||||
spi_rxpos = 0;
|
||||
|
||||
// enable SPI
|
||||
// SPI->CR1 |= SPI_CR1_SPE;
|
||||
|
||||
// enable tx/rx interrupt.
|
||||
// interrupt handler will deal with the transmission
|
||||
// SPI->CR2 |= SPI_CR2_TXEIE | SPI_CR2_RXNEIE;
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* returns whether the SPI peripheral is busy with a transfer.
|
||||
*/
|
||||
/*
|
||||
uint8_t spi_isbusy()
|
||||
{
|
||||
return spi_xfer_len ? 1 : 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* selects which mosi to activate.
|
||||
* note: when going from NONE to LED, must wait at least 1ms before
|
||||
* sending data. so just architect the system to never do this.
|
||||
*/
|
||||
void spi_mosi_sel(uint8_t which)
|
||||
{
|
||||
uint16_t moder;
|
||||
|
||||
moder = SPI_MOSI_SPI_PORT->MODER & \
|
||||
~((0x3 << (SPI_MOSI_SPI_PIN * 2)) | \
|
||||
(0x3 << (SPI_CLK_PIN * 2)) | \
|
||||
(0x3 << (SPI_MOSI_LED_PIN * 2)));
|
||||
|
||||
switch (which) {
|
||||
case SPI_MOSI_NONE: {
|
||||
SPI_MOSI_LED_PORT->BSRR = (1 << SPI_MOSI_LED_PIN);
|
||||
moder |= ( \
|
||||
(GPIO_Mode_OUT << (SPI_MOSI_SPI_PIN * 2)) | \
|
||||
(GPIO_Mode_OUT << (SPI_CLK_PIN * 2)) | \
|
||||
(GPIO_Mode_IN << (SPI_MOSI_LED_PIN * 2)));
|
||||
break;
|
||||
}
|
||||
case SPI_MOSI_SPI: {
|
||||
moder |= ( \
|
||||
(GPIO_Mode_AF << (SPI_MOSI_SPI_PIN * 2)) | \
|
||||
(GPIO_Mode_AF << (SPI_CLK_PIN * 2)) | \
|
||||
(GPIO_Mode_OUT << (SPI_MOSI_LED_PIN * 2)));
|
||||
break;
|
||||
}
|
||||
case SPI_MOSI_LED: {
|
||||
SPI_MOSI_LED_PORT->BRR = (1 << SPI_MOSI_LED_PIN);
|
||||
moder |= ( \
|
||||
(GPIO_Mode_OUT << (SPI_MOSI_SPI_PIN * 2)) | \
|
||||
(GPIO_Mode_OUT << (SPI_CLK_PIN * 2)) | \
|
||||
(GPIO_Mode_AF << (SPI_MOSI_LED_PIN * 2)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SPI_MOSI_SPI_PORT->MODER = moder;
|
||||
}
|
||||
|
||||
// interrupt handler
|
||||
/*
|
||||
__attribute__ ((long_call, section(".ramfunc"))) void SPI1_IRQHandler()
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
// transmit buffer
|
||||
if (SPI->SR & SPI_SR_TXE) {
|
||||
if (spi_txpos >= spi_xfer_len) {
|
||||
// we are done
|
||||
SPI->CR2 &= (uint16_t)(~(uint16_t)SPI_CR2_TXEIE);
|
||||
} else {
|
||||
// load next byte
|
||||
SPI_SendData8(SPI, spi_txbuf[spi_txpos++]);
|
||||
}
|
||||
}
|
||||
|
||||
if (SPI->SR & SPI_SR_RXNE) {
|
||||
data = SPI_ReceiveData8(SPI);
|
||||
if (spi_rxbuf) {
|
||||
spi_rxbuf[spi_rxpos++] = data;
|
||||
}
|
||||
|
||||
// are we done?
|
||||
if (spi_rxpos >= spi_xfer_len) {
|
||||
// we are done
|
||||
SPI->CR2 &= (uint16_t)(~(uint16_t)SPI_CR2_RXNEIE);
|
||||
spi_xfer_len = 0;
|
||||
|
||||
// disable SPI
|
||||
// SPI->CR1 &= (uint16_t)(~(uint16_t)SPI_CR1_SPE);
|
||||
|
||||
// do callback
|
||||
if (spi_done_cb) {
|
||||
spi_done_cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
41
badge_firmware/code/src/timer.c
Normal file
41
badge_firmware/code/src/timer.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* timer.c
|
||||
*
|
||||
* Created on: Jun 25, 2023
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
|
||||
#include "hk32f030m.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* main code loop setup
|
||||
*/
|
||||
void tim6_init()
|
||||
{
|
||||
NVIC_InitTypeDef nvic;
|
||||
|
||||
// enable timer clock
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
|
||||
|
||||
// configure timer for continuous 1KHz interrupt rate
|
||||
TIM6->CR1 = 0; // default settings
|
||||
TIM6->CNT = 0; // clear count
|
||||
TIM6->PSC = 16 - 1; // set prescale
|
||||
TIM6->ARR = (2000000 / 1024) - 1; // set interrupt frequency
|
||||
TIM6->EGR = TIM_EGR_UG; // reload values
|
||||
|
||||
// enable timer, send update event, clear interrupt then enable interrupt
|
||||
TIM6->SR = 0; // clear interrupt if set
|
||||
TIM6->CR1 = TIM_CR1_ARPE | \
|
||||
TIM_CR1_URS | TIM_CR1_CEN; // enable timer as upcounter
|
||||
TIM6->DIER = TIM_DIER_UIE; // enable interrupt source
|
||||
|
||||
// configure and enable IRQ
|
||||
nvic.NVIC_IRQChannel = TIM6_IRQn;
|
||||
nvic.NVIC_IRQChannelPriority = 1;
|
||||
nvic.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init(&nvic);
|
||||
}
|
||||
Reference in New Issue
Block a user