initial WIP
lots of code copied over, things filled in to hopefully get the LED matrix lighting up. untested.
This commit is contained in:
41
firmware/app/ch32x035_conf.h
Normal file
41
firmware/app/ch32x035_conf.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32x035_conf.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2023/04/06
|
||||
* Description : Library configuration file.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#ifndef __CH32X035_CONF_H
|
||||
#define __CH32X035_CONF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ch32x035_adc.h"
|
||||
#include "ch32x035_awu.h"
|
||||
#include "ch32x035_dbgmcu.h"
|
||||
#include "ch32x035_dma.h"
|
||||
#include "ch32x035_exti.h"
|
||||
#include "ch32x035_flash.h"
|
||||
#include "ch32x035_gpio.h"
|
||||
#include "ch32x035_i2c.h"
|
||||
#include "ch32x035_iwdg.h"
|
||||
#include "ch32x035_pwr.h"
|
||||
#include "ch32x035_rcc.h"
|
||||
#include "ch32x035_spi.h"
|
||||
#include "ch32x035_tim.h"
|
||||
#include "ch32x035_usart.h"
|
||||
#include "ch32x035_wwdg.h"
|
||||
#include "ch32x035_it.h"
|
||||
#include "ch32x035_misc.h"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
56
firmware/app/ch32x035_it.c
Normal file
56
firmware/app/ch32x035_it.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32x035_it.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2024/10/28
|
||||
* Description : Main Interrupt Service Routines.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#include "ch32x035_it.h"
|
||||
|
||||
#include "driver/adc.h"
|
||||
|
||||
|
||||
void NMI_Handler(void) __attribute__((interrupt)); //("WCH-Interrupt-fast")));
|
||||
void HardFault_Handler(void) __attribute__((interrupt)); //("WCH-Interrupt-fast")));
|
||||
|
||||
/*********************************************************************
|
||||
* @fn NMI_Handler
|
||||
*
|
||||
* @brief This function handles NMI exception.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn HardFault_Handler
|
||||
*
|
||||
* @brief This function handles Hard Fault exception.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ADC1_IRQHandler() __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
void ADC1_IRQHandler()
|
||||
{
|
||||
adc_isr();
|
||||
}
|
||||
|
||||
|
||||
20
firmware/app/ch32x035_it.h
Normal file
20
firmware/app/ch32x035_it.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : ch32x035_it.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2023/04/06
|
||||
* Description : This file contains the headers of the interrupt handlers.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#ifndef __CH32X035_IT_H
|
||||
#define __CH32X035_IT_H
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
92
firmware/app/comms/i2c.h
Normal file
92
firmware/app/comms/i2c.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* i2c.h
|
||||
*
|
||||
* Created on: Oct 13, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef USER_COMMS_I2C_H_
|
||||
#define USER_COMMS_I2C_H_
|
||||
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
|
||||
|
||||
|
||||
#define SOFT_I2C_MASTER
|
||||
|
||||
|
||||
|
||||
#ifdef SOFT_I2C_MASTER
|
||||
|
||||
|
||||
#include "soft_i2c_master.h"
|
||||
|
||||
/* known bugs / limitations:
|
||||
* - there is no ack on address. code always assumes slave is responding.
|
||||
*/
|
||||
#define i2c_init() i2cm_init()
|
||||
#define i2c_start() { SetSysClock_HSI(HCLK_24MHZ); i2cm_start(); }
|
||||
#define i2c_restart() i2cm_restart()
|
||||
#define i2c_stop() { i2cm_stop(); SetSysClock_HSI(HCLK_8MHZ); }
|
||||
#define i2c_rd(ack) i2cm_rd(ack)
|
||||
#define i2c_wr(dat) i2cm_wr(dat)
|
||||
#define i2c_addr(a, w) i2c_start(); i2cm_addr(a, w)
|
||||
|
||||
#define i2c_rdbuf(d, s) i2cm_rdbuf(d, s); i2c_stop()
|
||||
#define i2c_wrbuf(d, s) i2cm_wrbuf(d, s); i2c_stop()
|
||||
|
||||
|
||||
#define i2c_read(a, d, s) i2c_start(); \
|
||||
i2cm_addr(a, 1); \
|
||||
i2cm_rdbuf(d, s); \
|
||||
i2c_stop()
|
||||
|
||||
#define i2c_read_reg8(a, r, d, s) i2c_start(); \
|
||||
i2cm_addr(a, 0); \
|
||||
i2cm_wr(r); \
|
||||
i2cm_restart(); \
|
||||
i2cm_addr(a, 1); \
|
||||
i2cm_rdbuf(d, s); \
|
||||
i2c_stop()
|
||||
|
||||
#define i2c_read_reg16(a, r, d, s) i2c_start(); \
|
||||
i2cm_addr(a, 0); \
|
||||
i2cm_wr(r >> 8); \
|
||||
i2cm_wr(r & 0xff); \
|
||||
i2cm_restart(); \
|
||||
i2cm_addr(a, 1); \
|
||||
i2cm_rdbuf(d, s); \
|
||||
i2c_stop()
|
||||
|
||||
|
||||
#define i2c_write(a, d, s) i2c_start(); \
|
||||
i2cm_addr(a, 0); \
|
||||
i2cm_wrbuf(d, s); \
|
||||
i2c_stop()
|
||||
|
||||
#define i2c_write_reg8(a, r, d, s) i2c_start(); \
|
||||
i2cm_addr(a, 0); \
|
||||
i2cm_wr(r); \
|
||||
i2cm_wrbuf(d, s); \
|
||||
i2c_stop()
|
||||
|
||||
#define i2c_write_reg16(a, r, d, s) i2c_start(); \
|
||||
i2cm_addr(a, 0); \
|
||||
i2cm_wr(r >> 8); \
|
||||
i2cm_wr(r & 0xff); \
|
||||
i2cm_wrbuf(d, s); \
|
||||
i2c_stop()
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#error HW I2C NOT YET IMPLEMENTED!
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* USER_COMMS_I2C_H_ */
|
||||
222
firmware/app/comms/soft_i2c_master.c
Normal file
222
firmware/app/comms/soft_i2c_master.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* soft_i2c.c
|
||||
*
|
||||
* looked at random i2c code, used as inspiration, and wrote some
|
||||
* garbage for CH59x. then ported to CH32X035.
|
||||
*
|
||||
* i2c hardware peripheral on CH59x is shared with debug pins or.
|
||||
* USB pins. using both? touch shit, no I2C master periph for you.
|
||||
*
|
||||
* quirks, features and limitations:
|
||||
* - this implementation is blocking.
|
||||
* - clock stretching is supported, and somewhat tested
|
||||
* - any slave stuck clock stretching will lock everything until released;
|
||||
* there is no timeout or cancel operation implemented
|
||||
*
|
||||
* known good settings at 32MHz on CH59x:
|
||||
* CYCLES_TO_HI = 5, CYCLES_TO_LOW = 2: ~400-500kHz
|
||||
* CYCLES_TO_HI = 2, CYCLES_TO_LOW = 0: ~650KHz
|
||||
* CYCLES_TO_HI = 1, bit_delay_lo = __nop: ~900KHz, but sub MCU fails to respond
|
||||
*
|
||||
* speed settings chosen are what the lowest speed device (the sub MCU) will
|
||||
* handle without faults.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ch32x035_conf.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
#define CYCLES_TO_HI 2
|
||||
#define CYCLES_TO_LO 0
|
||||
|
||||
//#define CYCLES_RD 2 // cycles spent in read routine
|
||||
//#define CYCLES_WR_HI 2 // extra cycles spent in write routine
|
||||
//#define CYCLES_WR_LO 4
|
||||
|
||||
#define bit_delay_hi() { spin = delay_hi; while(spin--); }
|
||||
#define bit_delay_lo() { spin = delay_lo; while(spin--); }
|
||||
|
||||
#define rd_delay() bit_delay_hi()
|
||||
|
||||
#define wr_delay_hi() bit_delay_hi()
|
||||
#define wr_delay_lo() bit_delay_hi() // spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--)
|
||||
|
||||
|
||||
#define SDA_PIN 9
|
||||
#define SDA_BIT (1 << SDA_PIN)
|
||||
#define SDA_CONFOFF ((SDA_PIN % 8) * 4)
|
||||
#define SDA_GPIO GPIOB
|
||||
#define SDA_CFGR GPIOB->CFGHR
|
||||
|
||||
#define SCL_PIN 8
|
||||
#define SCL_BIT (1 << SCL_PIN)
|
||||
#define SCL_CONFOFF ((SCL_PIN % 8) * 4)
|
||||
#define SCL_GPIO GPIOB
|
||||
#define SCL_CFGR GPIOB->CFGHR
|
||||
|
||||
#define GPIO_CFG_LO 0x1
|
||||
#define GPIO_CFG_HI 0x8
|
||||
|
||||
|
||||
#define SDA_IN_HI() { SDA_CFGR &= ~(0xf << SDA_CONFOFF); SDA_CFGR |= (GPIO_CFG_HI << SDA_CONFOFF); }
|
||||
#define SDA_OUTLO() { SDA_CFGR &= ~(0xf << SDA_CONFOFF); SDA_CFGR |= (GPIO_CFG_LO << SDA_CONFOFF); }
|
||||
#define SDA_SET_LO() SDA_GPIO->BCR = SDA_BIT
|
||||
#define SDA_GET() ( SDA_GPIO->INDR & SDA_BIT )
|
||||
|
||||
#define SCL_IN_HI() { SCL_CFGR &= ~(0xf << SCL_CONFOFF); SCL_CFGR |= (GPIO_CFG_HI << SCL_CONFOFF); }
|
||||
#define SCL_OUTLO() { SCL_CFGR &= ~(0xf << SCL_CONFOFF); SCL_CFGR |= (GPIO_CFG_LO << SCL_CONFOFF); }
|
||||
#define SCL_SET_LO() SCL_GPIO->BCR = SCL_BIT
|
||||
#define SCL_GET() ( SCL_GPIO->INDR & SCL_BIT )
|
||||
|
||||
|
||||
|
||||
static uint16_t delay_hi, delay_lo;
|
||||
static volatile uint16_t spin;
|
||||
|
||||
|
||||
|
||||
// re-run init any time the clock speed changes to recalculate delays.
|
||||
void i2cm_init()
|
||||
{
|
||||
//uint32_t sysclk;
|
||||
//uint32_t cycles;
|
||||
|
||||
// configure GPIO
|
||||
SCL_IN_HI();
|
||||
SCL_SET_LO();
|
||||
|
||||
SDA_IN_HI();
|
||||
SDA_SET_LO();
|
||||
|
||||
// configure timer
|
||||
//sysclk = GetSysClock();
|
||||
//cycles = sysclk / 500000;
|
||||
|
||||
delay_hi = CYCLES_TO_HI;
|
||||
delay_lo = CYCLES_TO_LO;
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc")))
|
||||
void i2cm_start()
|
||||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
while (!SCL_GET()) {}; // clock stretch
|
||||
SDA_OUTLO(); bit_delay_lo();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc")))
|
||||
void i2cm_restart()
|
||||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()) {}; // clock stretch
|
||||
bit_delay_hi(); // attempt to fix corruption; unnecessary?
|
||||
i2cm_start();
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc")))
|
||||
void i2cm_stop()
|
||||
{
|
||||
SDA_OUTLO(); bit_delay_lo();
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
while (!SCL_GET()) {}; // clock stretch
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
bit_delay_hi();
|
||||
}
|
||||
|
||||
// returns: data byte
|
||||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_rd(uint8_t ack)
|
||||
{
|
||||
int8_t x;
|
||||
uint8_t in = 0;
|
||||
|
||||
SDA_IN_HI();
|
||||
|
||||
for (x = 8; x; x--) {
|
||||
in <<= 1; // clock next bit
|
||||
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()) {}; // clock stretch
|
||||
|
||||
rd_delay();
|
||||
|
||||
if (SDA_GET()) in |= 1;
|
||||
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
if (ack) { SDA_OUTLO(); } // ack
|
||||
else { SDA_IN_HI(); } // nack
|
||||
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
// returns: possible ack from target
|
||||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_wr(uint8_t dat)
|
||||
{
|
||||
int8_t x;
|
||||
uint8_t ack;
|
||||
|
||||
SCL_OUTLO();
|
||||
|
||||
for (x = 8; x; x--) {
|
||||
if (dat & 0x80) { SDA_IN_HI(); }
|
||||
else { SDA_OUTLO(); }
|
||||
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()) {}; // clock stretch
|
||||
wr_delay_hi();
|
||||
|
||||
dat <<= 1;
|
||||
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
SDA_IN_HI(); __asm__ volatile("nop"); // slave will now try to ack
|
||||
SCL_IN_HI(); bit_delay_hi();
|
||||
while (!SCL_GET()); // nothing should stretch here, but...
|
||||
|
||||
ack = SDA_GET();
|
||||
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
|
||||
return ack;
|
||||
}
|
||||
|
||||
// use a left-aligned address with this implementation.
|
||||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit)
|
||||
{
|
||||
addr &= 0xfe;
|
||||
addr |= reading_bit ? 1 : 0;
|
||||
return i2cm_wr(addr);
|
||||
}
|
||||
|
||||
|
||||
void i2cm_rdbuf(uint8_t *dat, uint16_t len)
|
||||
{
|
||||
while (len--) *dat++ = i2cm_rd(len > 0);
|
||||
// i2cm_stop();
|
||||
}
|
||||
|
||||
void i2cm_wrbuf(const uint8_t *dat, uint16_t len)
|
||||
{
|
||||
uint8_t nack;
|
||||
|
||||
while (len--) {
|
||||
nack = i2cm_wr(*dat++);
|
||||
if (nack) break;
|
||||
}
|
||||
// i2cm_stop();
|
||||
}
|
||||
28
firmware/app/comms/soft_i2c_master.h
Normal file
28
firmware/app/comms/soft_i2c_master.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* soft_i2c.h
|
||||
*/
|
||||
|
||||
#ifndef USER_COMM_SOFT_I2C_MASTER_H_
|
||||
#define USER_COMM_SOFT_I2C_MASTER_H_
|
||||
|
||||
#include <ch32x035.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
void i2cm_init();
|
||||
|
||||
void i2cm_start();
|
||||
void i2cm_restart();
|
||||
void i2cm_stop();
|
||||
|
||||
uint8_t i2cm_rd(uint8_t ack);
|
||||
uint8_t i2cm_wr(uint8_t dat);
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit);
|
||||
|
||||
void i2cm_rdbuf(uint8_t *dat, uint16_t len);
|
||||
void i2cm_wrbuf(const uint8_t *dat, uint16_t len);
|
||||
|
||||
|
||||
|
||||
#endif /* USER_COMM_SOFT_I2C_MASTER_H_ */
|
||||
67
firmware/app/comms/spi_master.c
Normal file
67
firmware/app/comms/spi_master.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* spi_master.c
|
||||
*
|
||||
* manage chip select externally.
|
||||
*
|
||||
* current version is BLOCKING. update later to use interrupt or DMA.
|
||||
*/
|
||||
|
||||
#include "spi_master.h"
|
||||
|
||||
|
||||
|
||||
void spim_init()
|
||||
{
|
||||
SPI_InitTypeDef spi = {0};
|
||||
|
||||
spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
|
||||
spi.SPI_Mode = SPI_Mode_Master;
|
||||
spi.SPI_DataSize = SPI_DataSize_8b;
|
||||
spi.SPI_CPOL = SPI_CPOL_High;
|
||||
spi.SPI_CPHA = SPI_CPHA_2Edge;
|
||||
spi.SPI_NSS = SPI_NSS_Soft;
|
||||
spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
|
||||
spi.SPI_FirstBit = SPI_FirstBit_MSB;
|
||||
|
||||
SPI_Init(SPI1, &spi);
|
||||
|
||||
SPI_Cmd(SPI1, ENABLE);
|
||||
}
|
||||
|
||||
void spim_write_raw(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
// todo: make non-blocking, timeout and error checking
|
||||
while (len) {
|
||||
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)) {
|
||||
SPI_I2S_SendData(SPI1, *data);
|
||||
data++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spim_write_reg8(uint8_t reg, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
spim_write_raw(®, 1);
|
||||
spim_write_raw(data, len);
|
||||
}
|
||||
|
||||
void spim_read_raw(uint8_t *data, uint16_t len)
|
||||
{
|
||||
// todo: non-blocking, timeout and error checking
|
||||
while (len) {
|
||||
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY)) {};
|
||||
|
||||
if (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)) {
|
||||
*data++ = SPI_I2S_ReceiveData(SPI1);
|
||||
len--;
|
||||
}
|
||||
SPI_I2S_SendData(SPI1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void spim_read_reg8(uint8_t reg, uint8_t *data, uint16_t len)
|
||||
{
|
||||
spim_write_raw(®, 1);
|
||||
spim_read_raw(data, len);
|
||||
}
|
||||
20
firmware/app/comms/spi_master.h
Normal file
20
firmware/app/comms/spi_master.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __APP_COMMS_SPI_MASTER_H
|
||||
#define __APP_COMMS_SPI_MASTER_H
|
||||
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
|
||||
|
||||
|
||||
void spim_init();
|
||||
|
||||
void spim_write_reg8(uint8_t reg, const uint8_t *data, uint16_t len);
|
||||
void spim_read_reg8(uint8_t reg, uint8_t *data, uint16_t len);
|
||||
|
||||
|
||||
|
||||
#endif /* __APP_COMMS_SPI_MASTER_H */
|
||||
168
firmware/app/driver/accel.c
Normal file
168
firmware/app/driver/accel.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* accel.c
|
||||
*
|
||||
* Created on: Oct 13, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
|
||||
#include "accel.h"
|
||||
#include "lis2hh12_reg.h"
|
||||
|
||||
#include "comms/spi_master.h"
|
||||
|
||||
#include "misc/i8atan2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
// user data
|
||||
AccelData accel;
|
||||
|
||||
uint8_t accel_found = 0;
|
||||
|
||||
uint8_t movement_idx; // index into "read" register
|
||||
int16_t movement_read[4]; // last read movement value
|
||||
int16_t movement; // last calculated movement value
|
||||
uint16_t movement_worst; // worst seen movement value
|
||||
|
||||
|
||||
// hardware
|
||||
static stmdev_ctx_t dev_ctx;
|
||||
|
||||
|
||||
|
||||
static int32_t accel_write(void *handle, uint8_t reg, const uint8_t *bufp, uint16_t len)
|
||||
{
|
||||
(void)(handle);
|
||||
|
||||
// i2c_write_reg8(LIS2_I2C_ADDR_SDO_LOW, reg, bufp, len);
|
||||
LIS2_CS_PORT->BCR = LIS2_CS_PIN;
|
||||
spim_write_reg8(reg, bufp, len);
|
||||
LIS2_CS_PORT->BSHR = LIS2_CS_PIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t accel_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len)
|
||||
{
|
||||
(void)(handle);
|
||||
|
||||
// i2c_read_reg8(LIS2DW_I2C_ADDR_SDO_LOW, reg, bufp, len);
|
||||
LIS2_CS_PORT->BCR = LIS2_CS_PIN;
|
||||
spim_read_reg8(reg, bufp, len);
|
||||
LIS2_CS_PORT->BSHR = LIS2_CS_PIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void accel_init()
|
||||
{
|
||||
uint8_t devid;
|
||||
uint8_t reset;
|
||||
uint16_t timeout = 1000;
|
||||
|
||||
dev_ctx.write_reg = accel_write;
|
||||
dev_ctx.read_reg = accel_read;
|
||||
|
||||
// make sure we've got the right device
|
||||
lis2hh12_dev_id_get(&dev_ctx, &devid);
|
||||
if (devid == LIS2HH12_ID) {
|
||||
accel_found = 1;
|
||||
}
|
||||
|
||||
// reset accelerometer
|
||||
if (accel_found) {
|
||||
lis2hh12_dev_reset_set(&dev_ctx, PROPERTY_ENABLE);
|
||||
do {
|
||||
lis2hh12_dev_reset_get(&dev_ctx, &reset);
|
||||
if (!reset) {
|
||||
timeout = 0;
|
||||
accel_found = 1;
|
||||
}
|
||||
} while (timeout--);
|
||||
}
|
||||
|
||||
if (accel_found) {
|
||||
// disable block update
|
||||
// data in output registers is updated immediately; FIFO is disabled
|
||||
lis2hh12_block_data_update_set(&dev_ctx, PROPERTY_DISABLE);
|
||||
|
||||
// configure scale, power mode
|
||||
lis2hh12_xl_full_scale_set(&dev_ctx, LIS2HH12_2g);
|
||||
// TODO: check this
|
||||
// lis2hh12_power_mode_set(&dev_ctx, LIS2DW12_CONT_LOW_PWR_LOW_NOISE_4);
|
||||
|
||||
// configure filter chain
|
||||
// low pass filter enabled for 6D (not currently used)
|
||||
lis2hh12_xl_filter_out_path_set(&dev_ctx, LIS2HH12_FILT_LP);
|
||||
// digital LPF2 filter of output data
|
||||
lis2hh12_xl_filter_low_bandwidth_set(&dev_ctx, LIS2HH12_LP_ODR_DIV_9);
|
||||
|
||||
// configure output data rate
|
||||
lis2hh12_xl_data_rate_set(&dev_ctx, LIS2HH12_XL_ODR_200Hz);
|
||||
}
|
||||
}
|
||||
|
||||
void accel_poll()
|
||||
{
|
||||
uint8_t reg = 1;
|
||||
int16_t xyz[3];
|
||||
|
||||
if (!accel_found) return;
|
||||
|
||||
while (reg) {
|
||||
// read output only if new value is available
|
||||
lis2hh12_xl_flag_data_ready_get(&dev_ctx, ®);
|
||||
|
||||
if (reg) {
|
||||
// read acceleration data
|
||||
memset(xyz, 0x00, 3 * sizeof(int16_t));
|
||||
lis2hh12_acceleration_raw_get(&dev_ctx, xyz);
|
||||
|
||||
accel.x = xyz[0] >>= 8;
|
||||
accel.y = xyz[1] >>= 8;
|
||||
accel.z = xyz[2] >>= 8;
|
||||
|
||||
// compute our shitty "movement" thing
|
||||
// awful way to detect being still
|
||||
reg = sizeof(movement_read) / sizeof(movement_read[0]);
|
||||
|
||||
movement_idx++;
|
||||
if (movement_idx == reg) {
|
||||
movement_idx = 0;
|
||||
movement = abs(movement_read[3] - movement_read[0]);
|
||||
if (movement > movement_worst) {
|
||||
movement_worst = movement;
|
||||
}
|
||||
}
|
||||
|
||||
movement_read[movement_idx] = abs(accel.x) + abs(accel.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t accel_get_rotation(struct AccelData *a)
|
||||
{
|
||||
int8_t nx, ny, ret;
|
||||
|
||||
nx = -a->x;
|
||||
ny = a->y;
|
||||
|
||||
ret = i8atan2(nx, ny) >> 1;
|
||||
if (ret < 0) {
|
||||
ret += 128;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int16_t accel_get_movement()
|
||||
{
|
||||
return movement;
|
||||
}
|
||||
48
firmware/app/driver/accel.h
Normal file
48
firmware/app/driver/accel.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* accel.h
|
||||
*
|
||||
* Created on: Oct 13, 2024
|
||||
* Author: true
|
||||
*/
|
||||
|
||||
#ifndef USER_MISC_ACCEL_H_
|
||||
#define USER_MISC_ACCEL_H_
|
||||
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
#define LIS2_CS_PORT GPIOB // CH32X035-specific
|
||||
#define LIS2_CS_PIN GPIO_Pin_6
|
||||
|
||||
#define LIS2_I2C_ADDR 0x30
|
||||
#define LIS2_I2C_ADDR_SDO_LOW 0x32
|
||||
|
||||
|
||||
|
||||
typedef struct AccelData {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
int16_t z;
|
||||
} AccelData;
|
||||
|
||||
|
||||
|
||||
extern AccelData accel;
|
||||
extern uint8_t accel_found;
|
||||
|
||||
extern uint16_t movement_worst;
|
||||
|
||||
|
||||
|
||||
void accel_init();
|
||||
void accel_poll();
|
||||
|
||||
int8_t accel_get_rotation(struct AccelData *a);
|
||||
int16_t accel_get_movement();
|
||||
|
||||
|
||||
|
||||
#endif /* USER_MISC_ACCEL_H_ */
|
||||
186
firmware/app/driver/adc.c
Normal file
186
firmware/app/driver/adc.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* adc.c
|
||||
*
|
||||
* todo:
|
||||
* - use DMA
|
||||
*/
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
|
||||
|
||||
#define ADC_CHANNELS 8
|
||||
|
||||
#define CHAN_ENABLED 0x80
|
||||
|
||||
#define CHAN_MASK 0x7f
|
||||
#define CHAN_IS_NORMAL 0
|
||||
#define CHAN_IS_TOUCH 1
|
||||
#define CHAN_IS_LIGHTSENSE 2
|
||||
|
||||
#define TOUCH_DEFAULT_CHARGE 0x88
|
||||
#define TOUCH_DEFAULT_THRESH 0x800
|
||||
|
||||
|
||||
typedef struct AdcChan {
|
||||
uint8_t chan; // ADC channel number
|
||||
uint8_t type; // ADC channel type (use above defines)
|
||||
uint8_t timing; // sample rate for normal channels, charge values for touch-type channels
|
||||
uint8_t idx; // rawval index
|
||||
uint16_t avg; // averaged output
|
||||
uint16_t thresh; // touch threshold
|
||||
uint16_t rawval[8]; // raw counts
|
||||
} AdcChan;
|
||||
|
||||
|
||||
static uint8_t adc_idx = 0;
|
||||
static AdcChan adc_chan[ADC_CHANNELS] = {0};
|
||||
|
||||
|
||||
|
||||
void adc_init()
|
||||
{
|
||||
ADC_InitTypeDef adc = {0};
|
||||
|
||||
// configure pin struct
|
||||
for (uint8_t i = 0; i < ADC_CHANNELS; i++) {
|
||||
adc_chan[i].type = CHAN_ENABLED | CHAN_IS_TOUCH;
|
||||
adc_chan[i].timing = TOUCH_DEFAULT_CHARGE;
|
||||
adc_chan[i].thresh = TOUCH_DEFAULT_THRESH;
|
||||
}
|
||||
|
||||
adc_chan[0].chan = ADC_Channel_0;
|
||||
adc_chan[1].chan = ADC_Channel_1;
|
||||
adc_chan[2].chan = ADC_Channel_2;
|
||||
adc_chan[3].chan = ADC_Channel_3;
|
||||
adc_chan[4].chan = ADC_Channel_4;
|
||||
adc_chan[5].chan = ADC_Channel_8;
|
||||
adc_chan[6].chan = ADC_Channel_13;
|
||||
|
||||
adc_chan[7].chan = ADC_Channel_9;
|
||||
adc_chan[7].type = CHAN_IS_LIGHTSENSE;
|
||||
adc_chan[7].timing = ADC_SampleTime_7Cycles;
|
||||
|
||||
|
||||
// configure actual peripheral
|
||||
ADC_DeInit(ADC1);
|
||||
|
||||
ADC_CLKConfig(ADC1, ADC_CLK_Div6);
|
||||
|
||||
adc.ADC_Mode = ADC_Mode_Independent;
|
||||
adc.ADC_ScanConvMode = DISABLE;
|
||||
adc.ADC_ContinuousConvMode = DISABLE;
|
||||
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
|
||||
adc.ADC_DataAlign = ADC_DataAlign_Right;
|
||||
adc.ADC_NbrOfChannel = 1;
|
||||
ADC_Init(ADC1, &adc);
|
||||
|
||||
ADC_Cmd(ADC1, ENABLE);
|
||||
}
|
||||
|
||||
int8_t adc_get_tkey(uint8_t key_idx)
|
||||
{
|
||||
if (key_idx > ADC_CHANNELS)
|
||||
return 0;
|
||||
|
||||
if (adc_chan[key_idx].avg < adc_chan[key_idx].thresh) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adc_next()
|
||||
{
|
||||
AdcChan *chan;
|
||||
uint8_t timeout = 0;
|
||||
|
||||
// todo:
|
||||
// lightsense is timing-sensitive. will need to have this as an overridden channel?
|
||||
|
||||
// get next index
|
||||
adc_idx++;
|
||||
if (adc_idx > (sizeof(adc_chan) / sizeof(adc_chan[0]))) {
|
||||
adc_idx = 0;
|
||||
}
|
||||
|
||||
// so long as the channel is enabled
|
||||
while (!(adc_chan[adc_idx].type & CHAN_ENABLED) && (timeout++ < ADC_CHANNELS)) {
|
||||
adc_idx++;
|
||||
}
|
||||
|
||||
// if nothing is enabled, break out
|
||||
if (timeout == ADC_CHANNELS)
|
||||
return;
|
||||
|
||||
chan = &adc_chan[adc_idx];
|
||||
|
||||
// configure sampling
|
||||
switch (chan->type) {
|
||||
case CHAN_IS_NORMAL: {
|
||||
TKey1->CTLR1 &= ~ADC_TKENABLE; // disable TouchKey
|
||||
|
||||
// we don't have any
|
||||
break;
|
||||
}
|
||||
case CHAN_IS_TOUCH: {
|
||||
TKey1->CTLR1 |= ADC_TKENABLE; // enable TouchKey
|
||||
|
||||
ADC_RegularChannelConfig(ADC1, chan->chan, 1, ADC_SampleTime_11Cycles);
|
||||
TKey1->IDATAR1 = chan->timing & 0xf0; // R32_TKEY1_CHGOFFSET Charging Time
|
||||
TKey1->RDATAR = chan->timing & 0x0f; // R32_TKEY1_ACT_DCG Discharging Time
|
||||
// per the RM, setting RDATAR (ACT_DCG) starts the conversion
|
||||
|
||||
break;
|
||||
}
|
||||
case CHAN_IS_LIGHTSENSE: {
|
||||
TKey1->CTLR1 &= ~ADC_TKENABLE; // disable TouchKey
|
||||
|
||||
// todo: use thresh as a "timeout" value maybe?
|
||||
// this way the other channels can be sampled, and each time we pass by
|
||||
// the lightsensor, if it isn't time to sample it, it is skipped.
|
||||
ADC_RegularChannelConfig(ADC1, chan->chan, 1, chan->timing & 0xf);
|
||||
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void adc_isr()
|
||||
{
|
||||
AdcChan *chan;
|
||||
uint32_t v = 0;
|
||||
uint8_t amax, ashift;
|
||||
|
||||
chan = &adc_chan[adc_idx];
|
||||
|
||||
// conversion done
|
||||
if (ADC1->STATR & ADC_EOC) {
|
||||
chan->rawval[chan->idx] = ADC1->RDATAR;
|
||||
|
||||
// how many averages should we do?
|
||||
switch (chan->type & CHAN_MASK) {
|
||||
case CHAN_IS_TOUCH: {
|
||||
amax = 4;
|
||||
ashift = 2;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
amax = 8;
|
||||
ashift = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
chan->idx++;
|
||||
if (chan->idx >= amax) {
|
||||
chan->idx = 0;
|
||||
for (int i = 0; i < amax; i++) {
|
||||
v += chan->rawval[i];
|
||||
}
|
||||
chan->avg = v >> ashift;
|
||||
}
|
||||
}
|
||||
|
||||
// flags cleared by software
|
||||
ADC1->STATR = 0;
|
||||
}
|
||||
22
firmware/app/driver/adc.h
Normal file
22
firmware/app/driver/adc.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __APP_DRIVER_ADC_H
|
||||
#define __APP_DRIVER_ADC_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
void adc_init();
|
||||
void adc_next();
|
||||
|
||||
int8_t adc_get_tkey(uint8_t key_idx);
|
||||
|
||||
void adc_isr();
|
||||
|
||||
|
||||
|
||||
#endif /* __APP_DRIVER_ADC_H */
|
||||
247
firmware/app/driver/aw20xxx.c
Normal file
247
firmware/app/driver/aw20xxx.c
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* awinic AW20108 / AW20072 / AW20054 / AW20036 LED Matrix Driver
|
||||
*
|
||||
* originally written by true in 2022
|
||||
* while sleep deprived for a super constrained mcu
|
||||
*
|
||||
* some bugs fixed for defcon 32 on aug 6-7, 2024
|
||||
* - don't remember what was fixed
|
||||
*
|
||||
* some bugs fixed for supercon on oct 15, 2024
|
||||
* - fixed support for AW20054, which only supports 9 rows
|
||||
* did this by respecting aw->rows
|
||||
*
|
||||
*
|
||||
* driver assumptions:
|
||||
* - rows and columns are as is ordered on the chip, lowest to highest
|
||||
* (if any are skipped, just skip this data in your buffer)
|
||||
* - buffer size does not need to encompass all possible LEDs, only those
|
||||
* which you have specified you are using.
|
||||
* ensure sizeof(aw->fade) == aw->rows + aw->cols
|
||||
* - duty cycle will be set automatically according to aw->cols
|
||||
* - all AW20xxx chips will operate on the same i2c bus
|
||||
* - a static data buffer is used
|
||||
*
|
||||
* driver notices:
|
||||
* - updates only happen one column at a time, and are blocking
|
||||
* (future version may implement a callback when each column is done)
|
||||
* - this driver has not yet implemented the pattern controller
|
||||
* - this driver has not yet implemented the GAIN register, except as
|
||||
* a global configuration, so dimming only operates 8-bit
|
||||
* (will be implemented later to allow for beyond-8-bit operation)
|
||||
* - this driver has not yet implemented FADEDIM mode
|
||||
*
|
||||
* if you need anything different, write it yourself
|
||||
*/
|
||||
|
||||
#include "aw20xxx.h"
|
||||
|
||||
|
||||
|
||||
#define AW20X_THIS_PAGE (aw->state & AW20X_STATE_PAGE_MASK)
|
||||
|
||||
#define AW20X_SET_PAGE(x) if (AW20X_THIS_PAGE != (x)) { \
|
||||
aw20x_page(aw, x); \
|
||||
aw->state &= ~AW20X_STATE_PAGE_MASK; \
|
||||
aw->state |= x; }
|
||||
|
||||
|
||||
|
||||
static uint8_t aw_buf[25]; // enough bytes for register and single column FADEDIM update (1 + (12*2))
|
||||
|
||||
|
||||
|
||||
void aw20x_page(struct AW20x *aw, uint8_t page)
|
||||
{
|
||||
// the datasheet isn't clear on this. the default is zero, and only the lower
|
||||
// three bits are specified. yet the DS says to send 0xCy where y is the page bits.
|
||||
// we'll just do what the DS says even though it contradicts itself.
|
||||
aw_buf[0] = 0xc0 | (page & AW20X_PAGE_MASK);
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_PAGE, aw_buf, 1);
|
||||
}
|
||||
|
||||
void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint8_t imax)
|
||||
{
|
||||
// set config register as specified
|
||||
aw->addr = addr;
|
||||
aw->cols = cols;
|
||||
aw->rows = rows;
|
||||
aw->config = imax & AW20X_CONF_IMAX_MASK;
|
||||
|
||||
// wake up (and set page to config page)
|
||||
aw20x_set_sleep(aw, 0);
|
||||
|
||||
// enabled columns
|
||||
aw_buf[0] = cols - 1;
|
||||
while (AW20X_I2C_busy()) {};
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_SIZE, aw_buf, 1);
|
||||
|
||||
// general config
|
||||
aw_buf[0] = imax & AW20X_CONF_IMAX_MASK;
|
||||
while (AW20X_I2C_busy()) {};
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_GCCR, aw_buf, 1);
|
||||
}
|
||||
|
||||
void aw20x_set_sleep(struct AW20x *aw, uint8_t sleep)
|
||||
{
|
||||
// make sure we're on the config page
|
||||
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
|
||||
|
||||
aw_buf[0] = sleep ? AW20X_SLPCR_SLEEP : 0;
|
||||
|
||||
// send sleep bit
|
||||
while (AW20X_I2C_busy()) {};
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_SLPCR, aw_buf, 1);
|
||||
|
||||
// set state
|
||||
if (sleep) aw->state |= AW20X_STATE_SLEEP_MASK;
|
||||
else aw->state &= ~AW20X_STATE_SLEEP_MASK;
|
||||
|
||||
// burn some cycles if we woke up
|
||||
if (!sleep) AW20X_INIT_DELAY();
|
||||
}
|
||||
|
||||
void aw20x_set_imax(struct AW20x *aw, uint8_t imax)
|
||||
{
|
||||
// make sure we're on the config page
|
||||
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
|
||||
|
||||
aw_buf[0] = imax & AW20X_CONF_IMAX_MASK;
|
||||
|
||||
// send imax
|
||||
while (AW20X_I2C_busy()) {};
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_GCCR, aw_buf, 1);
|
||||
|
||||
aw->config = imax & AW20X_CONF_IMAX_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* sends LED values to the chip
|
||||
*/
|
||||
void aw20x_set_fade(struct AW20x *aw)
|
||||
{
|
||||
uint8_t c;
|
||||
uint8_t row;
|
||||
uint8_t offset;
|
||||
|
||||
// make sure we're on the fade page
|
||||
AW20X_SET_PAGE(AW20X_PAGE2_FADE);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy()) {};
|
||||
|
||||
row = offset = 0;
|
||||
for (c = 0; c < aw->cols; c++) {
|
||||
// write to chip
|
||||
AW20X_I2C_writereg(aw->addr, offset, aw->fade + row, aw->rows);
|
||||
while (AW20X_I2C_busy());
|
||||
row += aw->rows;
|
||||
offset += AW20X_MAX_ROWS;
|
||||
}
|
||||
}
|
||||
|
||||
void aw20x_set_dim(struct AW20x *aw)
|
||||
{
|
||||
// todo: implement
|
||||
}
|
||||
|
||||
/*
|
||||
* sets all LEDs to the specified 6-bit DIM value.
|
||||
* used when just using FADE and 8-bit mode
|
||||
* to set initial and fine tune from IMAX the output current.
|
||||
*/
|
||||
void aw20x_set_dim_global(struct AW20x *aw, uint8_t dim)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t row;
|
||||
uint8_t offset;
|
||||
|
||||
// ceil
|
||||
if (dim > 0x3f) dim = 0x3f;
|
||||
|
||||
// make sure we're on the dim page
|
||||
AW20X_SET_PAGE(AW20X_PAGE1_DIM);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy()) {};
|
||||
|
||||
// clear buffer
|
||||
for (i = 0; i <= aw->rows; i++) aw_buf[i] = dim;
|
||||
|
||||
// send buffer for each column
|
||||
row = offset = 0;
|
||||
for (i = 0; i < aw->cols; i++) {
|
||||
AW20X_I2C_writereg(aw->addr, offset, aw_buf, aw->rows);
|
||||
while (AW20X_I2C_busy());
|
||||
row += aw->rows;
|
||||
offset += AW20X_MAX_ROWS;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void aw20x_commit_fadedim(struct AW20x *aw)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void aw20x_led_on(struct AW20x *aw, uint8_t first, uint8_t last, uint8_t on_bit)
|
||||
{
|
||||
|
||||
}
|
||||
/*
|
||||
* enables LEDs based on user LED count, zero-indexed
|
||||
* assumes AW20X_MAX_LEDON_BITS per row but will only turn on active defined rows
|
||||
* AW20036 would be 0-35, but AW20054 would be 0-71 and so on
|
||||
* for example, LEDs 8-12 on AW20054 with 9 roww enabled
|
||||
* would enable C0R8, C1R0, C1R1, C1R2. all other LEDs are disabled
|
||||
*
|
||||
* todo:
|
||||
* - read current state, and apply bitfields to the currently active state
|
||||
* - allow bypassing the readback for faster operation (such as setting all LEDs on at startup)
|
||||
* - make this more efficient (36 LEDs takes ~0.3ms on a 48MHz PIC!)
|
||||
*/
|
||||
void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last)
|
||||
{
|
||||
uint8_t c, r;
|
||||
uint8_t idx;
|
||||
uint8_t boff;
|
||||
uint8_t *buf;
|
||||
|
||||
// make sure we're on the config page
|
||||
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
|
||||
// don't touch the buffer until we are allowed
|
||||
while (AW20X_I2C_busy());
|
||||
|
||||
// bits are stored 6 bits per byte, 2 bytes per column, one bit for each row
|
||||
// for a maximum of the AW20X_MAX_ROWS of LED on bits
|
||||
// we only want to touch bits that exist on the chip and in the correct order
|
||||
idx = 0;
|
||||
for (c = 0; c < aw->cols; c++) {
|
||||
buf = &aw_buf[c*2];
|
||||
buf[0] = buf[1] = 0;
|
||||
boff = 0;
|
||||
for (r = 0; r < AW20X_MAX_LEDON_BITS*2; r++) {
|
||||
if (r + idx < first) continue; // only start at the first led
|
||||
if (r + idx > last) break; // and stop at the last
|
||||
|
||||
if (r >= aw->rows) continue; // max bits to process per row
|
||||
|
||||
if (r == AW20X_MAX_LEDON_BITS) { // only this many bits per byte
|
||||
boff += AW20X_MAX_LEDON_BITS;
|
||||
buf++;
|
||||
}
|
||||
|
||||
*buf |= (1 << (r - boff));
|
||||
}
|
||||
idx += AW20X_MAX_LEDON_BITS*2;
|
||||
}
|
||||
|
||||
AW20X_I2C_writereg(aw->addr, AW20X_REG_LEDON0, aw_buf, c*2);
|
||||
}
|
||||
|
||||
/*
|
||||
* disables LEDs based on user LED count, zero-indexed
|
||||
* (for example, LEDs 8-12 on AW20054 would enable C0R8, C0R9, C1R0, C1R1)
|
||||
*/
|
||||
void aw20x_led_disable(struct AW20x *aw, uint8_t first, uint8_t last)
|
||||
{
|
||||
|
||||
}
|
||||
194
firmware/app/driver/aw20xxx.h
Normal file
194
firmware/app/driver/aw20xxx.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* awinic AW20108 / AW20072 / AW20054 / AW20036 LED Matrix Driver
|
||||
*/
|
||||
|
||||
#ifndef AW20X_LED_MATRIX_H
|
||||
#define AW20X_LED_MATRIX_H
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../comms/i2c.h"
|
||||
|
||||
|
||||
|
||||
#define AW20X_INIT_DELAY() { uint16_t zz = 1000; while(zz--); }
|
||||
// burn cycles for ~200us
|
||||
|
||||
#define AW20X_MAX_COLS 9
|
||||
#define AW20X_MAX_ROWS 12
|
||||
|
||||
#define AW20X_MAX_LEDON_BITS 6
|
||||
|
||||
#define AW20X_ADDR_SCL 0x38 // AD pin tied to SCL
|
||||
#define AW20X_ADDR_SDA 0x39 // AD pin tied to SDA
|
||||
#define AW20X_ADDR_GND 0x3A // AD pin tied to GND
|
||||
#define AW20X_ADDR_VDD 0x3B // AD pin tied to VDD
|
||||
|
||||
#define AW20X_CONF_IMAX_MASK 0xf0 // 7:4
|
||||
#define AW20X_CONF_IMAX_OFFSET 4 // 7:4
|
||||
#define AW20X_CONF_ADDR_MASK 0x03 // 1:0
|
||||
#define AW20X_CONF_ADDR_OFFSET 0 // 1:0
|
||||
|
||||
#define AW20X_CONF_USE_FADEDIM 0x08 // aw20x.fade now becomes fadedim; updates are done with FADEDIM page
|
||||
// this mode uses 2 bytes per LED; dim as byte 0, fade as byte 1
|
||||
#define AW20X_CONF_USE_EXPEN 0x04 // sets GCCR.EXPEN=1; fade is now only 6 bits (not yet implemented)
|
||||
|
||||
#define AW20X_PAGE_MASK 0x07
|
||||
|
||||
#define AW20X_STATE_PAGE_MASK AW20X_PAGE_MASK
|
||||
#define AW20X_STATE_SLEEP_MASK 0x80
|
||||
|
||||
|
||||
#define AW20X_PAGE0_CONFIG 0x00 // function register
|
||||
#define AW20X_PAGE1_DIM 0x01 // 5:0 dim; 8 bits per LED
|
||||
#define AW20X_PAGE2_FADE 0x02 // 7:0 fade; 8 bits per LED
|
||||
#define AW20X_PAGE3_PATTERN 0x03 // 1:0 pattern; 8 bits per LED
|
||||
#define AW20X_PAGE4_DIMFADE 0x04 // 13:8 dim, 7:0 fade; 16 bits per LED
|
||||
#define AW20X_PAGE5_DFP 0x05 // 15:14 pat, 13:8 dim, 7:0 fade; 16 bits per LED
|
||||
|
||||
#define AW20X_REG_IDR 0x00 // R 7:0 chip ID {0x18}
|
||||
#define AW20X_REG_SLPCR 0x01 // RW 7 sleep {0x80}
|
||||
#define AW20X_REG_RSTR 0x02 // W 7:0 SW_RSTN (?)
|
||||
#define AW20X_REG_GCCR 0x03 // RW 7:3 IMAX(7:4), ALLON, -, -, EXPEN {0x10}
|
||||
#define AW20X_REG_FCD 0x04 // W 0 FCDE (fast clear display enable)
|
||||
#define AW20X_REG_CLKSYS 0x05 // RW 1:0 CLK_IO, CLK_SEL
|
||||
#define AW20X_REG_FLTCFG1 0x09 // RW 5:0 UVLOPE, OTPE, UVIE, OTIE, UVLOE, OTE
|
||||
#define AW20X_REG_FLTCFG2 0x0a // RW 3:2 UVTH
|
||||
#define AW20X_REG_ISRFLT 0x0b // RW 5:0 PAT2IS, PAT1IS, PAT0IS, -, -, UVLOIS, OTIS
|
||||
#define AW20X_REG_LEDON0 0x31 // W 5:0 ON0:ON5, same pattern through to LEDON17 (0x42)
|
||||
#define AW20X_REG_PATCR 0x43 // RW 6:0 PAT2IE, PAT1IE, PAT0IE, -, PAT2EN, PAT1EN, PAT0EN
|
||||
#define AW20X_REG_FADEH0 0x44 // RW 7:0 FADEH0
|
||||
#define AW20X_REG_FADEH1 0x45
|
||||
#define AW20X_REG_FADEH2 0x46
|
||||
#define AW20X_REG_FADEL0 0x47
|
||||
#define AW20X_REG_FADEL1 0x48
|
||||
#define AW20X_REG_FADEL2 0x49 // RW 7:0 FADEL2
|
||||
#define AW20X_REG_PAT0T0 0x4a // RW 7:0 T1[4], T2[4]
|
||||
#define AW20X_REG_PAT0T1 0x4b // RW 7:0 T3[4], T4[4]
|
||||
#define AW20X_REG_PAT0T2 0x4c // RW 7:0 LE[2], LB[2], LT(11:8)[4]
|
||||
#define AW20X_REG_PAT0T3 0x4d // RW 7:0 LT(7:0)
|
||||
#define AW20X_REG_PAT1T0 0x4e
|
||||
#define AW20X_REG_PAT1T1 0x4f
|
||||
#define AW20X_REG_PAT1T2 0x50
|
||||
#define AW20X_REG_PAT1T3 0x51
|
||||
#define AW20X_REG_PAT2T0 0x52
|
||||
#define AW20X_REG_PAT2T1 0x53
|
||||
#define AW20X_REG_PAT2T2 0x54
|
||||
#define AW20X_REG_PAT2T3 0x55
|
||||
#define AW20X_REG_PAT0CFG 0x56 // RW 2:0 SWITCH, RAMPE, PATMD
|
||||
#define AW20X_REG_PAT1CFG 0x57
|
||||
#define AW20X_REG_PAT2CFG 0x58
|
||||
#define AW20X_REG_PATGO 0x59 // RW 6:0 PAT2ST, PAT1ST, PAT0ST, -, RUN2, RUN1, RUN0
|
||||
#define AW20X_REG_SIZE 0x80 // RW 3:0 SWSEL
|
||||
#define AW20X_REG_PAGE 0xf0 // RW 2:0 page select, 0-5; available from all pages
|
||||
|
||||
#define AW20X_IDR_ID 0x18 // value for all chips in this series
|
||||
|
||||
#define AW20X_SLPCR_SLEEP 0x01 // sleep mode (default is HIGH / asleep)
|
||||
|
||||
#define AW20X_RSTR_SW_RSTN 0x01 // write value to soft reset the chip
|
||||
|
||||
#define AW20X_GCCR_IMAX 0xf0 // global current setting (default 20mA)
|
||||
#define AW20X_GCCR_ALLON 0x08 // 0=normal, 1=force all on
|
||||
#define AW20X_GCCR_EXPEN 0x01 // 0=fade is linear 8-bit, 1=fade is exponential 6-bit
|
||||
|
||||
#define AW20X_FCD_FCDE 0x01 // write value to clear display (DS doesn't specify; is this a blanker?)
|
||||
|
||||
#define AW20X_CLKSYS_CLK_IO 0x02 // 0=no clk output, 1=clk output on (output) CLKIO pin
|
||||
#define AW20X_CLKSYS_CLK_SEL 0x01 // 0=internal 4MHz, 1=use clk on (input) CLKIO pin
|
||||
|
||||
#define AW20X_FLTCFG1_UVLOPE 0x20 // 1=enable UVLO protection; chip sets SLPCR.SLEEP when ISRFLT.UVLOIS=1
|
||||
#define AW20X_FLTCFG1_OTPE 0x10 // 1=enable overtemp protection; chip sets SLPCR.SLEEP when ISRFLT.UVLOIS=1
|
||||
#define AW20X_FLTCFG1_UVIE 0x08 // 1=UVLO interrupt enable
|
||||
#define AW20X_FLTCFG1_OTIE 0x04 // 1=overtemp interrupt enable
|
||||
#define AW20X_FLTCFG1_UVLOE 0x02 // 1=enable UVLO detect
|
||||
#define AW20X_FLTCFG1_OTE 0x01 // 1=enable overtemp detect
|
||||
|
||||
#define AW20X_FLTCFG1_UVTH_2V0 (0x00 << 2) // UVLO threshold voltage
|
||||
#define AW20X_FLTCFG1_UVTH_2V1 (0x01 << 2) // UVLO threshold voltage
|
||||
#define AW20X_FLTCFG1_UVTH_2V2 (0x02 << 2) // UVLO threshold voltage
|
||||
#define AW20X_FLTCFG1_UVTH_2V3 (0x03 << 2) // UVLO threshold voltage
|
||||
|
||||
#define AW20X_ISRFLT_PAT2IS 0x40 // pattern controller 2 interrupt (finished breath loop)
|
||||
#define AW20X_ISRFLT_PAT1IS 0x20 // pattern controller 1 interrupt (finished breath loop)
|
||||
#define AW20X_ISRFLT_PAT0IS 0x10 // pattern controller 0 interrupt (finished breath loop)
|
||||
#define AW20X_ISRFLT_UVLOIS 0x02 // 0=normal, 1=UVLO detected
|
||||
#define AW20X_ISRFLT_OTIS 0x01 // 0=normal, 1=overtemp detected
|
||||
|
||||
// todo: fill in all values from PATCR onward
|
||||
|
||||
|
||||
|
||||
#define AW20X_SOFT_RESET AW20X_RSTR_SW_RSTN
|
||||
|
||||
enum aw20x_imax {
|
||||
AW20X_IMAX_10MA = 0x00,
|
||||
AW20X_IMAX_20MA = 0x10,
|
||||
AW20X_IMAX_30MA = 0x20,
|
||||
AW20X_IMAX_40MA = 0x30,
|
||||
AW20X_IMAX_60MA = 0x40,
|
||||
AW20X_IMAX_80MA = 0x50,
|
||||
AW20X_IMAX_120MA = 0x60,
|
||||
AW20X_IMAX_160MA = 0x70,
|
||||
AW20X_IMAX_3_3MA = 0x80,
|
||||
AW20X_IMAX_6_7MA = 0x90,
|
||||
AW20X_IMAX_10MA_2 = 0xa0,
|
||||
AW20X_IMAX_13_3MA = 0xb0,
|
||||
AW20X_IMAX_20MA_2 = 0xc0,
|
||||
AW20X_IMAX_26_7MA = 0xd0,
|
||||
AW20X_IMAX_40MA_2 = 0xe0,
|
||||
AW20X_IMAX_53_3MA = 0xf0
|
||||
};
|
||||
|
||||
enum aw20x_size {
|
||||
AW20X_SIZE_1COL = 0,
|
||||
AW20X_SIZE_2COL,
|
||||
AW20X_SIZE_3COL,
|
||||
AW20X_SIZE_4COL,
|
||||
AW20X_SIZE_5COL,
|
||||
AW20X_SIZE_6COL,
|
||||
AW20X_SIZE_7COL,
|
||||
AW20X_SIZE_8COL,
|
||||
AW20X_SIZE_9COL
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef SOFT_I2C_MASTER
|
||||
#define AW20X_I2C_busy() (0)
|
||||
#define AW20X_I2C_writereg(adr, reg, buf, siz) i2c_write_reg8(adr, reg, buf, siz)
|
||||
#else
|
||||
#define AW20X_I2C_busy() (0)
|
||||
#define AW20X_I2C_writereg(adr, reg, buf, siz) i2c_write_addr1b(adr, reg, buf, siz);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct AW20x {
|
||||
uint8_t addr;
|
||||
uint8_t config; // settings for the chip
|
||||
uint8_t state; // keeps track of active page, and high bit is set if asleep
|
||||
uint8_t cols; // highest column used by application, 1-9
|
||||
uint8_t rows; // highest row used by application, 1-12
|
||||
uint8_t pad[3];
|
||||
uint8_t *fade; // led buffer location for FADE (required), of size cols+rows
|
||||
uint8_t *gain; // led buffer location for GAIN (optional), of size cols+rows
|
||||
} AW20x;
|
||||
|
||||
|
||||
|
||||
void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint8_t imax);
|
||||
|
||||
void aw20x_set_sleep(struct AW20x *aw, uint8_t sleep);
|
||||
void aw20x_set_imax(struct AW20x *aw, uint8_t imax);
|
||||
|
||||
void aw20x_set_fade(struct AW20x *aw);
|
||||
void aw20x_set_dim_global(struct AW20x *aw, uint8_t dim);
|
||||
|
||||
void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last);
|
||||
|
||||
|
||||
|
||||
#endif /* AW02X_LED_MATRIX_H */
|
||||
2549
firmware/app/driver/lis2hh12_reg.c
Normal file
2549
firmware/app/driver/lis2hh12_reg.c
Normal file
File diff suppressed because it is too large
Load Diff
992
firmware/app/driver/lis2hh12_reg.h
Normal file
992
firmware/app/driver/lis2hh12_reg.h
Normal file
@@ -0,0 +1,992 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file lis2hh12_reg.h
|
||||
* @author Sensors Software Solution Team
|
||||
* @brief This file contains all the functions prototypes for the
|
||||
* lis2hh12_reg.c driver.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef LIS2HH12_REGS_H
|
||||
#define LIS2HH12_REGS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <math.h>
|
||||
|
||||
/** @addtogroup LIS2HH12
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/** @defgroup Endianness definitions
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DRV_BYTE_ORDER
|
||||
#ifndef __BYTE_ORDER__
|
||||
|
||||
#define DRV_LITTLE_ENDIAN 1234
|
||||
#define DRV_BIG_ENDIAN 4321
|
||||
|
||||
/** if _BYTE_ORDER is not defined, choose the endianness of your architecture
|
||||
* by uncommenting the define which fits your platform endianness
|
||||
*/
|
||||
//#define DRV_BYTE_ORDER DRV_BIG_ENDIAN
|
||||
#define DRV_BYTE_ORDER DRV_LITTLE_ENDIAN
|
||||
|
||||
#else /* defined __BYTE_ORDER__ */
|
||||
|
||||
#define DRV_LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
|
||||
#define DRV_BIG_ENDIAN __ORDER_BIG_ENDIAN__
|
||||
#define DRV_BYTE_ORDER __BYTE_ORDER__
|
||||
|
||||
#endif /* __BYTE_ORDER__*/
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
/** @defgroup STMicroelectronics sensors common types
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEMS_SHARED_TYPES
|
||||
#define MEMS_SHARED_TYPES
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t bit0 : 1;
|
||||
uint8_t bit1 : 1;
|
||||
uint8_t bit2 : 1;
|
||||
uint8_t bit3 : 1;
|
||||
uint8_t bit4 : 1;
|
||||
uint8_t bit5 : 1;
|
||||
uint8_t bit6 : 1;
|
||||
uint8_t bit7 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t bit7 : 1;
|
||||
uint8_t bit6 : 1;
|
||||
uint8_t bit5 : 1;
|
||||
uint8_t bit4 : 1;
|
||||
uint8_t bit3 : 1;
|
||||
uint8_t bit2 : 1;
|
||||
uint8_t bit1 : 1;
|
||||
uint8_t bit0 : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} bitwise_t;
|
||||
|
||||
#define PROPERTY_DISABLE (0U)
|
||||
#define PROPERTY_ENABLE (1U)
|
||||
|
||||
/** @addtogroup Interfaces_Functions
|
||||
* @brief This section provide a set of functions used to read and
|
||||
* write a generic register of the device.
|
||||
* MANDATORY: return 0 -> no Error.
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
typedef int32_t (*stmdev_write_ptr)(
|
||||
void *handle,
|
||||
uint8_t reg,
|
||||
const uint8_t *buf,
|
||||
uint16_t len);
|
||||
|
||||
typedef int32_t (*stmdev_read_ptr)(
|
||||
void *handle,
|
||||
uint8_t reg,
|
||||
uint8_t *buf,
|
||||
uint16_t len);
|
||||
|
||||
typedef void (*stmdev_mdelay_ptr)(uint32_t millisec);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/** Component mandatory fields **/
|
||||
stmdev_write_ptr write_reg;
|
||||
stmdev_read_ptr read_reg;
|
||||
/** Component optional fields **/
|
||||
stmdev_mdelay_ptr mdelay;
|
||||
/** Customizable optional pointer **/
|
||||
void *handle;
|
||||
|
||||
/** private data **/
|
||||
void *priv_data;
|
||||
} stmdev_ctx_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#endif /* MEMS_SHARED_TYPES */
|
||||
|
||||
#ifndef MEMS_UCF_SHARED_TYPES
|
||||
#define MEMS_UCF_SHARED_TYPES
|
||||
|
||||
/** @defgroup Generic address-data structure definition
|
||||
* @brief This structure is useful to load a predefined configuration
|
||||
* of a sensor.
|
||||
* You can create a sensor configuration by your own or using
|
||||
* Unico / Unicleo tools available on STMicroelectronics
|
||||
* web site.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t address;
|
||||
uint8_t data;
|
||||
} ucf_line_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#endif /* MEMS_UCF_SHARED_TYPES */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
/** @defgroup LIS2HH12_Infos
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/** I2C Device Address 8 bit format if SA0=0 -> 0x3D if SA0=1 -> 0x3B **/
|
||||
#define LIS2HH12_I2C_ADD_L 0x3DU
|
||||
#define LIS2HH12_I2C_ADD_H 0x3BU
|
||||
/** Device Identification (Who am I) **/
|
||||
#define LIS2HH12_ID 0x41U
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#define LIS2HH12_TEMP_L 0x0BU
|
||||
#define LIS2HH12_TEMP_H 0x0CU
|
||||
#define LIS2HH12_WHO_AM_I 0x0FU
|
||||
#define LIS2HH12_ACT_THS 0x1EU
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t ths : 7;
|
||||
uint8_t not_used_01 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t not_used_01 : 1;
|
||||
uint8_t ths : 7;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_act_ths_t;
|
||||
|
||||
#define LIS2HH12_ACT_DUR 0x1FU
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dur : 8;
|
||||
} lis2hh12_act_dur_t;
|
||||
|
||||
#define LIS2HH12_CTRL1 0x20U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t xen : 1;
|
||||
uint8_t yen : 1;
|
||||
uint8_t zen : 1;
|
||||
uint8_t bdu : 1;
|
||||
uint8_t odr : 3;
|
||||
uint8_t hr : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t hr : 1;
|
||||
uint8_t odr : 3;
|
||||
uint8_t bdu : 1;
|
||||
uint8_t zen : 1;
|
||||
uint8_t yen : 1;
|
||||
uint8_t xen : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl1_t;
|
||||
|
||||
#define LIS2HH12_CTRL2 0x21U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t hpis : 2;
|
||||
uint8_t fds : 1;
|
||||
uint8_t hpm : 2;
|
||||
uint8_t dfc : 2;
|
||||
uint8_t not_used_01 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t not_used_01 : 1;
|
||||
uint8_t dfc : 2;
|
||||
uint8_t hpm : 2;
|
||||
uint8_t fds : 1;
|
||||
uint8_t hpis : 2;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl2_t;
|
||||
|
||||
#define LIS2HH12_CTRL3 0x22U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t int1_drdy : 1;
|
||||
uint8_t int1_fth : 1;
|
||||
uint8_t int1_ovr : 1;
|
||||
uint8_t int1_ig1 : 1;
|
||||
uint8_t int1_ig2 : 1;
|
||||
uint8_t int1_inact : 1;
|
||||
uint8_t stop_fth : 1;
|
||||
uint8_t fifo_en : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t fifo_en : 1;
|
||||
uint8_t stop_fth : 1;
|
||||
uint8_t int1_inact : 1;
|
||||
uint8_t int1_ig2 : 1;
|
||||
uint8_t int1_ig1 : 1;
|
||||
uint8_t int1_ovr : 1;
|
||||
uint8_t int1_fth : 1;
|
||||
uint8_t int1_drdy : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl3_t;
|
||||
|
||||
#define LIS2HH12_CTRL4 0x23U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t sim : 1;
|
||||
uint8_t i2c_disable : 1;
|
||||
uint8_t if_add_inc : 1;
|
||||
uint8_t bw_scale_odr : 1;
|
||||
uint8_t fs : 2;
|
||||
uint8_t bw : 2;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t bw : 2;
|
||||
uint8_t fs : 2;
|
||||
uint8_t bw_scale_odr : 1;
|
||||
uint8_t if_add_inc : 1;
|
||||
uint8_t i2c_disable : 1;
|
||||
uint8_t sim : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl4_t;
|
||||
|
||||
#define LIS2HH12_CTRL5 0x24U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t pp_od : 1;
|
||||
uint8_t h_lactive : 1;
|
||||
uint8_t st : 2;
|
||||
uint8_t dec : 2;
|
||||
uint8_t soft_reset : 1;
|
||||
uint8_t debug : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t debug : 1;
|
||||
uint8_t soft_reset : 1;
|
||||
uint8_t dec : 2;
|
||||
uint8_t st : 2;
|
||||
uint8_t h_lactive : 1;
|
||||
uint8_t pp_od : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl5_t;
|
||||
|
||||
#define LIS2HH12_CTRL6 0x25U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t int2_drdy : 1;
|
||||
uint8_t int2_fth : 1;
|
||||
uint8_t int2_empty : 1;
|
||||
uint8_t int2_ig1 : 1;
|
||||
uint8_t int2_ig2 : 1;
|
||||
uint8_t int2_boot : 1;
|
||||
uint8_t not_used_01 : 1;
|
||||
uint8_t boot : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t boot : 1;
|
||||
uint8_t not_used_01 : 1;
|
||||
uint8_t int2_boot : 1;
|
||||
uint8_t int2_ig2 : 1;
|
||||
uint8_t int2_ig1 : 1;
|
||||
uint8_t int2_empty : 1;
|
||||
uint8_t int2_fth : 1;
|
||||
uint8_t int2_drdy : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl6_t;
|
||||
|
||||
#define LIS2HH12_CTRL7 0x26U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t _4d_ig : 2;
|
||||
uint8_t lir : 2;
|
||||
uint8_t dcrm : 2;
|
||||
uint8_t not_used_01 : 2;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t not_used_01 : 2;
|
||||
uint8_t dcrm : 2;
|
||||
uint8_t lir : 2;
|
||||
uint8_t _4d_ig : 2;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ctrl7_t;
|
||||
|
||||
#define LIS2HH12_STATUS 0x27U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t xda : 1;
|
||||
uint8_t yda : 1;
|
||||
uint8_t zda : 1;
|
||||
uint8_t zyxda : 1;
|
||||
uint8_t _xor : 1;
|
||||
uint8_t yor : 1;
|
||||
uint8_t zor : 1;
|
||||
uint8_t zyxor : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t zyxor : 1;
|
||||
uint8_t zor : 1;
|
||||
uint8_t yor : 1;
|
||||
uint8_t _xor : 1;
|
||||
uint8_t zyxda : 1;
|
||||
uint8_t zda : 1;
|
||||
uint8_t yda : 1;
|
||||
uint8_t xda : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_status_t;
|
||||
|
||||
#define LIS2HH12_OUT_X_L 0x28U
|
||||
#define LIS2HH12_OUT_X_H 0x29U
|
||||
#define LIS2HH12_OUT_Y_L 0x2AU
|
||||
#define LIS2HH12_OUT_Y_H 0x2BU
|
||||
#define LIS2HH12_OUT_Z_L 0x2CU
|
||||
#define LIS2HH12_OUT_Z_H 0x2DU
|
||||
#define LIS2HH12_FIFO_CTRL 0x2EU
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t fth : 5;
|
||||
uint8_t fmode : 3;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t fmode : 3;
|
||||
uint8_t fth : 5;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_fifo_ctrl_t;
|
||||
|
||||
#define LIS2HH12_FIFO_SRC 0x2FU
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t fss : 5;
|
||||
uint8_t empty : 1;
|
||||
uint8_t ovr : 1;
|
||||
uint8_t fth : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t fth : 1;
|
||||
uint8_t ovr : 1;
|
||||
uint8_t empty : 1;
|
||||
uint8_t fss : 5;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_fifo_src_t;
|
||||
|
||||
#define LIS2HH12_IG_CFG1 0x30U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t xlie : 1;
|
||||
uint8_t xhie : 1;
|
||||
uint8_t ylie : 1;
|
||||
uint8_t yhie : 1;
|
||||
uint8_t zlie : 1;
|
||||
uint8_t zhie : 1;
|
||||
uint8_t _6d : 1;
|
||||
uint8_t aoi : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t aoi : 1;
|
||||
uint8_t _6d : 1;
|
||||
uint8_t zhie : 1;
|
||||
uint8_t zlie : 1;
|
||||
uint8_t yhie : 1;
|
||||
uint8_t ylie : 1;
|
||||
uint8_t xhie : 1;
|
||||
uint8_t xlie : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ig_cfg1_t;
|
||||
|
||||
#define LIS2HH12_IG_SRC1 0x31U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t xl : 1;
|
||||
uint8_t xh : 1;
|
||||
uint8_t yl : 1;
|
||||
uint8_t yh : 1;
|
||||
uint8_t zl : 1;
|
||||
uint8_t zh : 1;
|
||||
uint8_t ia : 1;
|
||||
uint8_t not_used_01 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t not_used_01 : 1;
|
||||
uint8_t ia : 1;
|
||||
uint8_t zh : 1;
|
||||
uint8_t zl : 1;
|
||||
uint8_t yh : 1;
|
||||
uint8_t yl : 1;
|
||||
uint8_t xh : 1;
|
||||
uint8_t xl : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ig_src1_t;
|
||||
|
||||
#define LIS2HH12_IG_THS_X1 0x32U
|
||||
#define LIS2HH12_IG_THS_Y1 0x33U
|
||||
#define LIS2HH12_IG_THS_Z1 0x34U
|
||||
#define LIS2HH12_IG_DUR1 0x35U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t dur1 : 7;
|
||||
uint8_t wait1 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t wait1 : 1;
|
||||
uint8_t dur1 : 7;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ig_dur1_t;
|
||||
|
||||
#define LIS2HH12_IG_CFG2 0x36U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t xlie : 1;
|
||||
uint8_t xhie : 1;
|
||||
uint8_t ylie : 1;
|
||||
uint8_t yhie : 1;
|
||||
uint8_t zlie : 1;
|
||||
uint8_t zhie : 1;
|
||||
uint8_t _6d : 1;
|
||||
uint8_t aoi : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t aoi : 1;
|
||||
uint8_t _6d : 1;
|
||||
uint8_t zhie : 1;
|
||||
uint8_t zlie : 1;
|
||||
uint8_t yhie : 1;
|
||||
uint8_t ylie : 1;
|
||||
uint8_t xhie : 1;
|
||||
uint8_t xlie : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ig_cfg2_t;
|
||||
|
||||
#define LIS2HH12_IG_SRC2 0x37U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t xl : 1;
|
||||
uint8_t xh : 1;
|
||||
uint8_t yl : 1;
|
||||
uint8_t yh : 1;
|
||||
uint8_t zl : 1;
|
||||
uint8_t zh : 1;
|
||||
uint8_t ia : 1;
|
||||
uint8_t not_used_01 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t not_used_01 : 1;
|
||||
uint8_t ia : 1;
|
||||
uint8_t zh : 1;
|
||||
uint8_t zl : 1;
|
||||
uint8_t yh : 1;
|
||||
uint8_t yl : 1;
|
||||
uint8_t xh : 1;
|
||||
uint8_t xl : 1;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ig_src2_t;
|
||||
|
||||
#define LIS2HH12_IG_THS2 0x38U
|
||||
#define LIS2HH12_IG_DUR2 0x39U
|
||||
typedef struct
|
||||
{
|
||||
#if DRV_BYTE_ORDER == DRV_LITTLE_ENDIAN
|
||||
uint8_t dur2 : 7;
|
||||
uint8_t wait2 : 1;
|
||||
#elif DRV_BYTE_ORDER == DRV_BIG_ENDIAN
|
||||
uint8_t wait2 : 1;
|
||||
uint8_t dur2 : 7;
|
||||
#endif /* DRV_BYTE_ORDER */
|
||||
} lis2hh12_ig_dur2_t;
|
||||
|
||||
#define LIS2HH12_XL_REFERENCE 0x3AU
|
||||
#define LIS2HH12_XH_REFERENCE 0x3BU
|
||||
#define LIS2HH12_YL_REFERENCE 0x3CU
|
||||
#define LIS2HH12_YH_REFERENCE 0x3DU
|
||||
#define LIS2HH12_ZL_REFERENCE 0x3EU
|
||||
#define LIS2HH12_ZH_REFERENCE 0x3FU
|
||||
|
||||
/**
|
||||
* @defgroup LIS2HH12_Register_Union
|
||||
* @brief This union group all the registers having a bit-field
|
||||
* description.
|
||||
* This union is useful but it's not needed by the driver.
|
||||
*
|
||||
* REMOVING this union you are compliant with:
|
||||
* MISRA-C 2012 [Rule 19.2] -> " Union are not allowed "
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
lis2hh12_act_ths_t act_ths;
|
||||
lis2hh12_act_dur_t act_dur;
|
||||
lis2hh12_ctrl1_t ctrl1;
|
||||
lis2hh12_ctrl2_t ctrl2;
|
||||
lis2hh12_ctrl3_t ctrl3;
|
||||
lis2hh12_ctrl4_t ctrl4;
|
||||
lis2hh12_ctrl5_t ctrl5;
|
||||
lis2hh12_ctrl6_t ctrl6;
|
||||
lis2hh12_ctrl7_t ctrl7;
|
||||
lis2hh12_status_t status;
|
||||
lis2hh12_fifo_ctrl_t fifo_ctrl;
|
||||
lis2hh12_fifo_src_t fifo_src;
|
||||
lis2hh12_ig_cfg1_t ig_cfg1;
|
||||
lis2hh12_ig_src1_t ig_src1;
|
||||
lis2hh12_ig_dur1_t ig_dur1;
|
||||
lis2hh12_ig_cfg2_t ig_cfg2;
|
||||
lis2hh12_ig_src2_t ig_src2;
|
||||
lis2hh12_ig_dur2_t ig_dur2;
|
||||
bitwise_t bitwise;
|
||||
uint8_t byte;
|
||||
} lis2hh12_reg_t;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif /* __weak */
|
||||
|
||||
/*
|
||||
* These are the basic platform dependent I/O routines to read
|
||||
* and write device registers connected on a standard bus.
|
||||
* The driver keeps offering a default implementation based on function
|
||||
* pointers to read/write routines for backward compatibility.
|
||||
* The __weak directive allows the final application to overwrite
|
||||
* them with a custom implementation.
|
||||
*/
|
||||
|
||||
int32_t lis2hh12_read_reg(const stmdev_ctx_t *ctx, uint8_t reg,
|
||||
uint8_t *data,
|
||||
uint16_t len);
|
||||
int32_t lis2hh12_write_reg(const stmdev_ctx_t *ctx, uint8_t reg,
|
||||
uint8_t *data,
|
||||
uint16_t len);
|
||||
|
||||
float_t lis2hh12_from_fs2g_to_mg(int16_t lsb);
|
||||
float_t lis2hh12_from_fs4g_to_mg(int16_t lsb);
|
||||
float_t lis2hh12_from_fs8g_to_mg(int16_t lsb);
|
||||
|
||||
float_t lis2hh12_from_lsb_to_celsius(int16_t lsb);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t xen : 1;
|
||||
uint8_t yen : 1;
|
||||
uint8_t zen : 1;
|
||||
} lis2hh12_xl_axis_t;
|
||||
int32_t lis2hh12_xl_axis_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_axis_t val);
|
||||
int32_t lis2hh12_xl_axis_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_axis_t *val);
|
||||
|
||||
int32_t lis2hh12_block_data_update_set(const stmdev_ctx_t *ctx,
|
||||
uint8_t val);
|
||||
int32_t lis2hh12_block_data_update_get(const stmdev_ctx_t *ctx,
|
||||
uint8_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_XL_ODR_OFF = 0x00,
|
||||
LIS2HH12_XL_ODR_10Hz = 0x01,
|
||||
LIS2HH12_XL_ODR_50Hz = 0x02,
|
||||
LIS2HH12_XL_ODR_100Hz = 0x03,
|
||||
LIS2HH12_XL_ODR_200Hz = 0x04,
|
||||
LIS2HH12_XL_ODR_400Hz = 0x05,
|
||||
LIS2HH12_XL_ODR_800Hz = 0x06,
|
||||
} lis2hh12_xl_data_rate_t;
|
||||
int32_t lis2hh12_xl_data_rate_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_data_rate_t val);
|
||||
int32_t lis2hh12_xl_data_rate_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_data_rate_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_2g = 0x00,
|
||||
LIS2HH12_4g = 0x02,
|
||||
LIS2HH12_8g = 0x03,
|
||||
} lis2hh12_xl_fs_t;
|
||||
int32_t lis2hh12_xl_full_scale_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_fs_t val);
|
||||
int32_t lis2hh12_xl_full_scale_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_fs_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_NO_DECIMATION = 0x00,
|
||||
LIS2HH12_EVERY_2_SAMPLES = 0x01,
|
||||
LIS2HH12_EVERY_4_SAMPLES = 0x02,
|
||||
LIS2HH12_EVERY_8_SAMPLES = 0x03,
|
||||
} lis2hh12_dec_t;
|
||||
int32_t lis2hh12_xl_decimation_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_dec_t val);
|
||||
int32_t lis2hh12_xl_decimation_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_dec_t *val);
|
||||
|
||||
int32_t lis2hh12_xl_flag_data_ready_get(const stmdev_ctx_t *ctx,
|
||||
uint8_t *val);
|
||||
|
||||
int32_t lis2hh12_temperature_raw_get(const stmdev_ctx_t *ctx, int16_t *val);
|
||||
|
||||
int32_t lis2hh12_acceleration_raw_get(const stmdev_ctx_t *ctx,
|
||||
int16_t *val);
|
||||
|
||||
int32_t lis2hh12_dev_id_get(const stmdev_ctx_t *ctx, uint8_t *buff);
|
||||
|
||||
int32_t lis2hh12_dev_reset_set(const stmdev_ctx_t *ctx, uint8_t val);
|
||||
int32_t lis2hh12_dev_reset_get(const stmdev_ctx_t *ctx, uint8_t *val);
|
||||
|
||||
int32_t lis2hh12_dev_boot_set(const stmdev_ctx_t *ctx, uint8_t val);
|
||||
int32_t lis2hh12_dev_boot_get(const stmdev_ctx_t *ctx, uint8_t *val);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t xda : 1;
|
||||
uint8_t yda : 1;
|
||||
uint8_t zda : 1;
|
||||
uint8_t zyxda : 1;
|
||||
uint8_t _xor : 1;
|
||||
uint8_t yor : 1;
|
||||
uint8_t zor : 1;
|
||||
uint8_t zyxor : 1;
|
||||
} lis2hh12_status_reg_t;
|
||||
int32_t lis2hh12_dev_status_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_status_reg_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_HP_DISABLE = 0x00,
|
||||
LIS2HH12_HP_ON_INT_GEN_1 = 0x02,
|
||||
LIS2HH12_HP_ON_INT_GEN_2 = 0x01,
|
||||
LIS2HH12_HP_ON_BOTH_GEN = 0x03,
|
||||
} lis2hh12_xl_hp_path_t;
|
||||
int32_t lis2hh12_xl_filter_int_path_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_hp_path_t val);
|
||||
int32_t lis2hh12_xl_filter_int_path_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_hp_path_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_BYPASSED = 0x00,
|
||||
LIS2HH12_FILT_HP = 0x02,
|
||||
LIS2HH12_FILT_LP = 0x01,
|
||||
} lis2hh12_xl_out_path_t;
|
||||
int32_t lis2hh12_xl_filter_out_path_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_out_path_t val);
|
||||
int32_t lis2hh12_xl_filter_out_path_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_out_path_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_HP_ODR_DIV_50 = 0x00,
|
||||
LIS2HH12_HP_ODR_DIV_100 = 0x10,
|
||||
LIS2HH12_HP_ODR_DIV_9 = 0x20,
|
||||
LIS2HH12_HP_ODR_DIV_400 = 0x30,
|
||||
LIS2HH12_HP_ODR_DIV_50_REF_MD = 0x01,
|
||||
LIS2HH12_HP_ODR_DIV_100_REF_MD = 0x11,
|
||||
LIS2HH12_HP_ODR_DIV_9_REF_MD = 0x21,
|
||||
LIS2HH12_HP_ODR_DIV_400_REF_MD = 0x31,
|
||||
} lis2hh12_xl_hp_bw_t;
|
||||
int32_t lis2hh12_xl_filter_hp_bandwidth_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_hp_bw_t val);
|
||||
int32_t lis2hh12_xl_filter_hp_bandwidth_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_hp_bw_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_LP_ODR_DIV_50 = 0,
|
||||
LIS2HH12_LP_ODR_DIV_100 = 1,
|
||||
LIS2HH12_LP_ODR_DIV_9 = 2,
|
||||
LIS2HH12_LP_ODR_DIV_400 = 3,
|
||||
} lis2hh12_xl_lp_bw_t;
|
||||
int32_t lis2hh12_xl_filter_low_bandwidth_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_lp_bw_t val);
|
||||
int32_t lis2hh12_xl_filter_low_bandwidth_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_lp_bw_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_AUTO = 0x00,
|
||||
LIS2HH12_408Hz = 0x10,
|
||||
LIS2HH12_211Hz = 0x11,
|
||||
LIS2HH12_105Hz = 0x12,
|
||||
LIS2HH12_50Hz = 0x13,
|
||||
} lis2hh12_xl_filt_aa_bw_t;
|
||||
int32_t lis2hh12_xl_filter_aalias_bandwidth_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_filt_aa_bw_t val);
|
||||
int32_t lis2hh12_xl_filter_aalias_bandwidth_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_filt_aa_bw_t *val);
|
||||
|
||||
int32_t lis2hh12_xl_filter_reference_set(const stmdev_ctx_t *ctx,
|
||||
int16_t *val);
|
||||
int32_t lis2hh12_xl_filter_reference_get(const stmdev_ctx_t *ctx,
|
||||
int16_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_SPI_4_WIRE = 0x00,
|
||||
LIS2HH12_SPI_3_WIRE = 0x01,
|
||||
} lis2hh12_sim_t;
|
||||
int32_t lis2hh12_spi_mode_set(const stmdev_ctx_t *ctx, lis2hh12_sim_t val);
|
||||
int32_t lis2hh12_spi_mode_get(const stmdev_ctx_t *ctx, lis2hh12_sim_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_I2C_ENABLE = 0x00,
|
||||
LIS2HH12_I2C_DISABLE = 0x01,
|
||||
} lis2hh12_i2c_dis_t;
|
||||
int32_t lis2hh12_i2c_interface_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_i2c_dis_t val);
|
||||
int32_t lis2hh12_i2c_interface_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_i2c_dis_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_DISABLE = 0x00,
|
||||
LIS2HH12_ENABLE = 0x01,
|
||||
} lis2hh12_auto_inc_t;
|
||||
int32_t lis2hh12_auto_increment_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_auto_inc_t val);
|
||||
int32_t lis2hh12_auto_increment_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_auto_inc_t *val);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t int1_drdy : 1;
|
||||
uint8_t int1_fth : 1;
|
||||
uint8_t int1_ovr : 1;
|
||||
uint8_t int1_ig1 : 1;
|
||||
uint8_t int1_ig2 : 1;
|
||||
uint8_t int1_inact : 1;
|
||||
} lis2hh12_pin_int1_route_t;
|
||||
int32_t lis2hh12_pin_int1_route_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_int1_route_t val);
|
||||
int32_t lis2hh12_pin_int1_route_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_int1_route_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_PUSH_PULL = 0x00,
|
||||
LIS2HH12_OPEN_DRAIN = 0x01,
|
||||
} lis2hh12_pp_od_t;
|
||||
int32_t lis2hh12_pin_mode_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pp_od_t val);
|
||||
int32_t lis2hh12_pin_mode_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pp_od_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_ACTIVE_HIGH = 0x00,
|
||||
LIS2HH12_ACTIVE_LOW = 0x01,
|
||||
} lis2hh12_pin_pol_t;
|
||||
int32_t lis2hh12_pin_polarity_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_pol_t val);
|
||||
int32_t lis2hh12_pin_polarity_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_pol_t *val);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t int2_drdy : 1;
|
||||
uint8_t int2_fth : 1;
|
||||
uint8_t int2_empty : 1;
|
||||
uint8_t int2_ig1 : 1;
|
||||
uint8_t int2_ig2 : 1;
|
||||
uint8_t int2_boot : 1;
|
||||
} lis2hh12_pin_int2_route_t;
|
||||
int32_t lis2hh12_pin_int2_route_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_int2_route_t val);
|
||||
int32_t lis2hh12_pin_int2_route_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_int2_route_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_INT_PULSED = 0x00,
|
||||
LIS2HH12_INT_LATCHED = 0x01,
|
||||
} lis2hh12_lir_t;
|
||||
int32_t lis2hh12_pin_notification_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_lir_t val);
|
||||
int32_t lis2hh12_pin_notification_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_lir_t *val);
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_IG1_OR_IG2_OR = 0x00,
|
||||
LIS2HH12_IG1_AND_IG2_OR = 0x01,
|
||||
LIS2HH12_IG1_OR_IG2_AND = 0x10,
|
||||
LIS2HH12_IG1_AND_IG2_AND = 0x11,
|
||||
} lis2hh12_pin_logic_t;
|
||||
int32_t lis2hh12_pin_logic_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_logic_t val);
|
||||
int32_t lis2hh12_pin_logic_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_pin_logic_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_RESET_MODE = 0x00,
|
||||
LIS2HH12_DECREMENT_MODE = 0x01,
|
||||
} lis2hh12_dcrm_t;
|
||||
int32_t lis2hh12_xl_trshld_mode_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_dcrm_t val);
|
||||
int32_t lis2hh12_xl_trshld_mode_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_dcrm_t *val);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t ig1_xlie : 1;
|
||||
uint16_t ig1_xhie : 1;
|
||||
uint16_t ig1_ylie : 1;
|
||||
uint16_t ig1_yhie : 1;
|
||||
uint16_t ig1_zlie : 1;
|
||||
uint16_t ig1_zhie : 1;
|
||||
uint16_t ig2_xlie : 1;
|
||||
uint16_t ig2_xhie : 1;
|
||||
uint16_t ig2_ylie : 1;
|
||||
uint16_t ig2_yhie : 1;
|
||||
uint16_t ig2_zlie : 1;
|
||||
uint16_t ig2_zhie : 1;
|
||||
} lis2hh12_xl_trshld_en_t;
|
||||
int32_t lis2hh12_xl_trshld_axis_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_trshld_en_t val);
|
||||
int32_t lis2hh12_xl_trshld_axis_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_trshld_en_t *val);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t ig1_xl : 1;
|
||||
uint16_t ig1_xh : 1;
|
||||
uint16_t ig1_yl : 1;
|
||||
uint16_t ig1_yh : 1;
|
||||
uint16_t ig1_zl : 1;
|
||||
uint16_t ig1_zh : 1;
|
||||
uint16_t ig1_ia : 1;
|
||||
uint16_t ig2_xl : 1;
|
||||
uint16_t ig2_xh : 1;
|
||||
uint16_t ig2_yl : 1;
|
||||
uint16_t ig2_yh : 1;
|
||||
uint16_t ig2_zl : 1;
|
||||
uint16_t ig2_zh : 1;
|
||||
uint16_t ig2_ia : 1;
|
||||
} lis2hh12_xl_trshld_src_t;
|
||||
int32_t lis2hh12_xl_trshld_src_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_trshld_src_t *val);
|
||||
|
||||
int32_t lis2hh12_xl_trshld_set(const stmdev_ctx_t *ctx, uint8_t ig1_x,
|
||||
uint8_t ig1_y, uint8_t ig1_z,
|
||||
uint8_t ig2_xyz);
|
||||
int32_t lis2hh12_xl_trshld_get(const stmdev_ctx_t *ctx, uint8_t *ig1_x,
|
||||
uint8_t *ig1_y, uint8_t *ig1_z,
|
||||
uint8_t *ig2_xyz);
|
||||
|
||||
int32_t lis2hh12_xl_trshld_min_sample_set(const stmdev_ctx_t *ctx,
|
||||
uint8_t ig1_sam, uint8_t ig2_sam);
|
||||
int32_t lis2hh12_xl_trshld_min_sample_get(const stmdev_ctx_t *ctx,
|
||||
uint8_t *ig1_sam, uint8_t *ig2_sam);
|
||||
|
||||
int32_t lis2hh12_act_threshold_set(const stmdev_ctx_t *ctx, uint8_t val);
|
||||
int32_t lis2hh12_act_threshold_get(const stmdev_ctx_t *ctx, uint8_t *val);
|
||||
|
||||
int32_t lis2hh12_act_duration_set(const stmdev_ctx_t *ctx, uint8_t val);
|
||||
int32_t lis2hh12_act_duration_get(const stmdev_ctx_t *ctx, uint8_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_6D_4D_DISABLE = 0x00,
|
||||
LIS2HH12_ENABLE_ON_IG1_6D = 0x01,
|
||||
LIS2HH12_ENABLE_ON_IG2_6D = 0x02,
|
||||
LIS2HH12_ENABLE_ON_IG1_4D = 0x11,
|
||||
LIS2HH12_ENABLE_ON_IG2_4D = 0x12,
|
||||
} lis2hh12_6d_mode_t;
|
||||
int32_t lis2hh12_6d_mode_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_6d_mode_t val);
|
||||
int32_t lis2hh12_6d_mode_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_6d_mode_t *val);
|
||||
|
||||
int32_t lis2hh12_fifo_watermark_set(const stmdev_ctx_t *ctx, uint8_t val);
|
||||
int32_t lis2hh12_fifo_watermark_get(const stmdev_ctx_t *ctx, uint8_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_FIFO_OFF = 0x00,
|
||||
LIS2HH12_BYPASS_MODE = 0x10,
|
||||
LIS2HH12_FIFO_MODE = 0x11,
|
||||
LIS2HH12_STREAM_MODE = 0x12,
|
||||
LIS2HH12_STREAM_TO_FIFO_MODE = 0x13,
|
||||
LIS2HH12_BYPASS_TO_STREAM_MODE = 0x14,
|
||||
LIS2HH12_BYPASS_TO_FIFO_MODE = 0x17,
|
||||
} lis2hh12_fifo_md_t;
|
||||
int32_t lis2hh12_fifo_mode_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_fifo_md_t val);
|
||||
int32_t lis2hh12_fifo_mode_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_fifo_md_t *val);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t fss : 5;
|
||||
uint8_t empty : 1;
|
||||
uint8_t ovr : 1;
|
||||
uint8_t fth : 1;
|
||||
} lis2hh12_fifo_stat_t;
|
||||
int32_t lis2hh12_fifo_status_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_fifo_stat_t *val);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS2HH12_ST_DISABLE = 0x00,
|
||||
LIS2HH12_ST_POSITIVE = 0x01,
|
||||
LIS2HH12_ST_NEGATIVE = 0x02,
|
||||
} lis2hh12_xl_st_t;
|
||||
int32_t lis2hh12_xl_self_test_set(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_st_t val);
|
||||
int32_t lis2hh12_xl_self_test_get(const stmdev_ctx_t *ctx,
|
||||
lis2hh12_xl_st_t *val);
|
||||
|
||||
/**
|
||||
*@}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIS2HH12_REGS_H */
|
||||
81
firmware/app/led/ledprog.c
Normal file
81
firmware/app/led/ledprog.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* ledprog.c: led programs
|
||||
*/
|
||||
|
||||
#include "matrix.h"
|
||||
|
||||
|
||||
|
||||
static uint32_t s[8] = {0};
|
||||
//static uint32_t t[8] = {0};
|
||||
//static uint32_t l[8] = {0};
|
||||
|
||||
|
||||
|
||||
void lp_ribbon_init()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
s[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void lp_ribbon_upward(uint16_t wait, uint16_t rate, uint8_t fade)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t x;
|
||||
|
||||
/*
|
||||
0: state
|
||||
1: timeout
|
||||
2: index
|
||||
*/
|
||||
switch (s[0]) {
|
||||
case 0: { // timeout
|
||||
if (!s[1]) {
|
||||
s[0]++;
|
||||
s[2] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s[1]--;
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: { // upward trails
|
||||
// rate delay
|
||||
if (!s[1]) {
|
||||
s[1] = rate;
|
||||
} else {
|
||||
s[1]--;
|
||||
break;
|
||||
}
|
||||
|
||||
x = s[2]++;
|
||||
|
||||
// are we done?
|
||||
if (x > sizeof(led_set.ribbon)) {
|
||||
s[0] = 0;
|
||||
s[1] = wait;
|
||||
break;
|
||||
}
|
||||
|
||||
// fade in and up
|
||||
led_set.ribbon[x] = 0x40;
|
||||
if (x) led_set.ribbon[x - 1] = 0x70;
|
||||
if (x > 1) led_set.ribbon[x - 2] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
// fade out LEDs
|
||||
for (i = 0; i < sizeof(led_set.ribbon); i++) {
|
||||
if (led_set.ribbon[i] >= fade) {
|
||||
led_set.ribbon[i] -= fade;
|
||||
} else {
|
||||
led_set.ribbon[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
matrix_flag_update();
|
||||
}
|
||||
15
firmware/app/led/ledprog.h
Normal file
15
firmware/app/led/ledprog.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* ledprog.h
|
||||
*/
|
||||
|
||||
#ifndef __APP_LED_LEDPROG_H
|
||||
#define __APP_LED_LEDPROG_H
|
||||
|
||||
|
||||
|
||||
void lp_ribbon_init();
|
||||
void lp_ribbon_upward(uint16_t wait, uint16_t rate, uint8_t fade);
|
||||
|
||||
|
||||
|
||||
#endif /* __APP_LED_LEDPROG_H */
|
||||
0
firmware/app/led/lightsense.c
Normal file
0
firmware/app/led/lightsense.c
Normal file
0
firmware/app/led/lightsense.h
Normal file
0
firmware/app/led/lightsense.h
Normal file
128
firmware/app/led/matrix.c
Normal file
128
firmware/app/led/matrix.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "matrix.h"
|
||||
#include "driver/aw20xxx.h"
|
||||
// #include "user_config.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#define AW20X_DIM 31 // initial global current setting
|
||||
|
||||
#define AW20X_COLS 6
|
||||
#define AW20X_ROWS 12
|
||||
#define AW20X_FADE_COUNT (AW20X_ROWS * AW20X_COLS)
|
||||
|
||||
#define HWEN_PORT GPIOB
|
||||
#define HWEN_PIN GPIO_Pin_7
|
||||
|
||||
|
||||
AW20x awled;
|
||||
static uint8_t awled_fade[AW20X_FADE_COUNT];
|
||||
|
||||
static uint8_t led_matrix_needs_update = 0;
|
||||
|
||||
uint16_t led_map_size;
|
||||
const LedMap led_map = {
|
||||
// map is 1-based to match part numbers on the board
|
||||
{ // ribbon
|
||||
1, 25, 13, 49,
|
||||
37, 14,
|
||||
28, 2, 38,
|
||||
50, 3,
|
||||
27, 15,
|
||||
39, 51,
|
||||
4, 16,
|
||||
28, 40,
|
||||
52, 5,
|
||||
17, 29,
|
||||
41, 53,
|
||||
6, 18,
|
||||
30, 42,
|
||||
54,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
7, 0,
|
||||
19, 0,
|
||||
31, 0,
|
||||
43, 0,
|
||||
55, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 20, 32,
|
||||
0, 0
|
||||
},
|
||||
{ // "A"
|
||||
9, 21, 33, 0, 0, 0, 45, 57, 10,
|
||||
22,
|
||||
34, 46, 58, 11, 23, 35, 47, 59, 12
|
||||
},
|
||||
{ // "//" left one
|
||||
61, 62, 63, 64, 44
|
||||
},
|
||||
{ // "//" right one
|
||||
60, 48, 36, 24, 56
|
||||
}
|
||||
};
|
||||
|
||||
LedMap led_set;
|
||||
|
||||
|
||||
void matrix_init()
|
||||
{
|
||||
volatile uint32_t x;
|
||||
|
||||
// make sure the hardware pin is on before calling.
|
||||
HWEN_PORT->BSHR = HWEN_PIN;
|
||||
|
||||
// wait a little while to ensure controller is awake
|
||||
x = 131072;
|
||||
while (x--);
|
||||
|
||||
// clear fade
|
||||
memset(awled_fade, 0x00, sizeof(awled_fade));
|
||||
|
||||
// set up RGBLED chip
|
||||
awled.fade = awled_fade;
|
||||
aw20x_init(&awled, AW20X_ADDR_VDD << 1, AW20X_COLS, AW20X_ROWS, AW20X_IMAX_20MA);
|
||||
|
||||
aw20x_set_dim_global(&awled, AW20X_DIM);
|
||||
aw20x_set_fade(&awled);
|
||||
aw20x_led_enable_range(&awled, 0, (AW20X_COLS * AW20X_MAX_ROWS) - 1);
|
||||
|
||||
led_map_size = sizeof(led_map.ribbon) + sizeof(led_map.a) + sizeof(led_map.ii_lf) + sizeof(led_map.ii_rt);
|
||||
}
|
||||
|
||||
void matrix_flag_update()
|
||||
{
|
||||
led_matrix_needs_update = 1;
|
||||
}
|
||||
|
||||
void matrix_send()
|
||||
{
|
||||
int8_t i;
|
||||
uint8_t *fade = awled_fade;
|
||||
uint8_t *map = (uint8_t *)&led_map;
|
||||
uint8_t *set = (uint8_t *)&led_set;
|
||||
|
||||
if (led_matrix_needs_update) {
|
||||
led_matrix_needs_update = 0;
|
||||
|
||||
// remap data for sending
|
||||
for (i = 0; i < led_map_size; i++) {
|
||||
if ((*map) & (*map <= AW20X_FADE_COUNT)) {
|
||||
fade[*map - 1] = *set;
|
||||
}
|
||||
map++;
|
||||
set++;
|
||||
}
|
||||
|
||||
aw20x_set_fade(&awled);
|
||||
}
|
||||
}
|
||||
35
firmware/app/led/matrix.h
Normal file
35
firmware/app/led/matrix.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __APP_LED_MATRIX_H
|
||||
#define __APP_LED_MATRIX_H
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
// 0 index = bottom.
|
||||
// 0 value = no LED here.
|
||||
typedef struct LedMap {
|
||||
uint8_t ribbon[80]; // a "linear" bottom to top map, with gaps for the spacing.
|
||||
uint8_t a[20]; // left to right, bottom to apex to bottom.
|
||||
uint8_t ii_lf[5]; // top to bottom.
|
||||
uint8_t ii_rt[5]; // top to bottom.
|
||||
} LedMap;
|
||||
|
||||
|
||||
|
||||
extern LedMap led_set;
|
||||
|
||||
|
||||
|
||||
void matrix_init();
|
||||
void matrix_send();
|
||||
|
||||
void matrix_flag_update();
|
||||
|
||||
|
||||
|
||||
#endif /* __APP_LED_MATRIX_H */
|
||||
175
firmware/app/main.c
Normal file
175
firmware/app/main.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* HSC26 Artemis II
|
||||
*
|
||||
* 2026 true
|
||||
*
|
||||
* todo:
|
||||
* - implement SPI master for accelerometer (done, blocking / basic)
|
||||
* - configure ADC to get touchpads (done)
|
||||
* - get main tick interrupt working
|
||||
*
|
||||
* - get user input working (buttons, touchpads)
|
||||
* - configure accelerometer for wakeup / sleep
|
||||
* - configure buttons to wake up in case of sleep
|
||||
* - write lightshows
|
||||
* - write userconfig stuff, save to end of FLASH
|
||||
*/
|
||||
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
|
||||
#include "comms/soft_i2c_master.h"
|
||||
#include "comms/spi_master.h"
|
||||
|
||||
#include "driver/adc.h"
|
||||
|
||||
#include "led/matrix.h"
|
||||
#include "led/ledprog.h"
|
||||
|
||||
/*
|
||||
*@Note
|
||||
***Only PA0--PA15 and PC16--PC17 support input pull-down.
|
||||
*/
|
||||
|
||||
|
||||
uint16_t cnt = 0;
|
||||
volatile uint32_t wake_uptime = 0;
|
||||
|
||||
volatile uint8_t lp_render = 0;
|
||||
|
||||
|
||||
|
||||
void clk_init()
|
||||
{
|
||||
SystemCoreClockUpdate();
|
||||
}
|
||||
|
||||
|
||||
void periphclk_init()
|
||||
{
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
|
||||
RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO |
|
||||
RCC_APB2Periph_ADC1 | RCC_APB2Periph_SPI1, ENABLE);
|
||||
|
||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 | RCC_AHBPeriph_USBPD, ENABLE);
|
||||
}
|
||||
|
||||
void gpio_init()
|
||||
{
|
||||
GPIO_InitTypeDef gpio = {0};
|
||||
|
||||
gpio.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
|
||||
// PA0-PA4 touch0-touch4
|
||||
gpio.GPIO_Mode = GPIO_Mode_AIN;
|
||||
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
|
||||
GPIO_Init(GPIOA, &gpio);
|
||||
// PB0 touch8
|
||||
gpio.GPIO_Pin = GPIO_Pin_0;
|
||||
GPIO_Init(GPIOB, &gpio);
|
||||
// PC0 VBAT, PC3 touch13
|
||||
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3;
|
||||
GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// PA5 SCK, PA7 MOSI
|
||||
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
|
||||
GPIO_Init(GPIOA, &gpio);
|
||||
|
||||
// PA6 MISO
|
||||
gpio.GPIO_Mode = GPIO_Mode_IPU;
|
||||
gpio.GPIO_Pin = GPIO_Pin_6;
|
||||
GPIO_Init(GPIOA, &gpio);
|
||||
|
||||
// PB3 LIS_INT, PB8 soft I2C SCL, PB9 soft I2C SDA, PB11 btn0, PB12 btn1
|
||||
gpio.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_12;
|
||||
GPIO_Init(GPIOB, &gpio);
|
||||
|
||||
// PC10 USB DP (btn2), PC11 USB DM (unused)
|
||||
gpio.GPIO_Mode = GPIO_Mode_IPD;
|
||||
gpio.GPIO_Pin = GPIO_Pin_16 | GPIO_Pin_17;
|
||||
GPIO_Init(GPIOC, &gpio);
|
||||
|
||||
// PB4 LSENS A, PB5 LSENS_K, PB6 SPI softCS, PB7 LED HWEN, PB10 STAT LED
|
||||
GPIOB->BCR = 0x4f0;
|
||||
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10;
|
||||
GPIO_Init(GPIOB, &gpio);
|
||||
|
||||
// PC14 CC1, PC15 CC2
|
||||
// todo later
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn main
|
||||
*
|
||||
* @brief Main program.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
|
||||
|
||||
clk_init();
|
||||
periphclk_init();
|
||||
gpio_init();
|
||||
|
||||
// initialize led programs
|
||||
lp_ribbon_init();
|
||||
|
||||
// set up soft I2C and configure lighting controller
|
||||
i2cm_init();
|
||||
matrix_init();
|
||||
|
||||
// set up touchsensing and light sensing
|
||||
adc_init();
|
||||
|
||||
// set up accelerometer
|
||||
spim_init();
|
||||
|
||||
// configure AWU to provide ~1440Hz wakeup interrupt for main program
|
||||
// TODO: confirm if the counter is reset / preloaded
|
||||
AWU_SetPrescaler(AWU_Prescaler_32);
|
||||
AWU_SetWindowValue(0x3e);
|
||||
AutoWakeUpCmd(ENABLE);
|
||||
|
||||
while (1) {
|
||||
// low-priority tasks like
|
||||
// rendering next LED program output frame
|
||||
if (lp_render) {
|
||||
lp_render = 0;
|
||||
lp_ribbon_upward(800, 3, 2);
|
||||
}
|
||||
|
||||
// stay a while
|
||||
// __WFI();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AWU_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
|
||||
void AWU_IRQHandler(void)
|
||||
{
|
||||
cnt++;
|
||||
if (cnt >= 1440) {
|
||||
cnt = 0;
|
||||
wake_uptime++;
|
||||
}
|
||||
|
||||
// handle render new frame at 90Hz
|
||||
if ((cnt & 0xf) == 0) {
|
||||
lp_render = 1;
|
||||
}
|
||||
|
||||
// send led matrix data to matrix chip
|
||||
matrix_send();
|
||||
|
||||
// handle ADC
|
||||
|
||||
// handle buttons
|
||||
|
||||
// do we sleep?
|
||||
}
|
||||
50
firmware/app/misc/i8atan2.c
Normal file
50
firmware/app/misc/i8atan2.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* i8atan2.c
|
||||
* begin 20190611 true
|
||||
*
|
||||
* copied and fixed up from teh internets
|
||||
*/
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
firmware/app/misc/i8atan2.h
Normal file
21
firmware/app/misc/i8atan2.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* i8atan2.h
|
||||
* begin 20190611 true
|
||||
*
|
||||
* copied and fixed up from teh internets
|
||||
*/
|
||||
|
||||
#ifndef INC_I8ATAN2_H_
|
||||
#define INC_I8ATAN2_H_
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
int8_t i8atan2(int8_t y, int8_t x);
|
||||
|
||||
|
||||
|
||||
#endif /* INC_I8ATAN2_H_ */
|
||||
101
firmware/app/system_ch32x035.c
Normal file
101
firmware/app/system_ch32x035.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : system_ch32x035.c
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2023/04/06
|
||||
* Description : CH32X035 Device Peripheral Access Layer System Source File.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#include "ch32x035.h"
|
||||
|
||||
/*
|
||||
* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after
|
||||
* reset the HSI is used as SYSCLK source).
|
||||
*/
|
||||
|
||||
//#define SYSCLK_FREQ_8MHz_HSI 8000000
|
||||
//#define SYSCLK_FREQ_12MHz_HSI 12000000
|
||||
//#define SYSCLK_FREQ_16MHz_HSI 16000000
|
||||
//#define SYSCLK_FREQ_24MHz_HSI 24000000
|
||||
//#define SYSCLK_FREQ_48MHz_HSI HSI_VALUE
|
||||
|
||||
/* Clock Definitions */
|
||||
uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
|
||||
|
||||
__I uint8_t AHBPrescTable[16] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SystemInit
|
||||
*
|
||||
* @brief Setup the microcontroller system Initialize the Embedded Flash Interface,
|
||||
* update the SystemCoreClock variable.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SystemInit(void)
|
||||
{
|
||||
RCC->CTLR |= (uint32_t)0x00000001;
|
||||
RCC->CFGR0 |= (uint32_t)0x00000050;
|
||||
RCC->CFGR0 &= (uint32_t)0xF8FFFF5F;
|
||||
SetSysClock_HSI(HCLK_24MHZ);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SystemCoreClockUpdate
|
||||
*
|
||||
* @brief Update SystemCoreClock variable according to Clock Register Values.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
|
||||
|
||||
if(((RCC->CFGR0 & RCC_HPRE) >> 4) < 8)
|
||||
{
|
||||
SystemCoreClock /= tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemCoreClock >>= tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn SetSysClock_HSI
|
||||
*
|
||||
* @brief Sets System clock frequency to specified and configure HCLK prescalers.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void SetSysClock_HSI(uint32_t divider)
|
||||
{
|
||||
uint32_t actlr;
|
||||
|
||||
/* Flash 2 wait state */
|
||||
actlr = FLASH->ACTLR & ((uint32_t)~FLASH_ACTLR_LATENCY);
|
||||
FLASH->ACTLR = actlr | (uint32_t)FLASH_ACTLR_LATENCY_2;
|
||||
|
||||
/* HCLK = SYSCLK = APB1 */
|
||||
RCC->CFGR0 &= (uint32_t)0xFFFFFF0F;
|
||||
RCC->CFGR0 |= (uint32_t)divider;
|
||||
|
||||
// set wait states depending on speed
|
||||
if (divider > RCC_HPRE_DIV1) { // 48MHz is already set to 2 cycles
|
||||
if (divider >= RCC_HPRE_DIV1) { // 24MHz is 1 cycle
|
||||
actlr |= (uint32_t)FLASH_ACTLR_LATENCY_0;
|
||||
} else { // all others are 0 cycle
|
||||
actlr |= (uint32_t)FLASH_ACTLR_LATENCY_1;
|
||||
}
|
||||
|
||||
FLASH->ACTLR = actlr;
|
||||
}
|
||||
}
|
||||
51
firmware/app/system_ch32x035.h
Normal file
51
firmware/app/system_ch32x035.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/********************************** (C) COPYRIGHT *******************************
|
||||
* File Name : system_ch32x035.h
|
||||
* Author : WCH
|
||||
* Version : V1.0.0
|
||||
* Date : 2023/04/06
|
||||
* Description : CH32X035 Device Peripheral Access Layer System Header File.
|
||||
*********************************************************************************
|
||||
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||
* Attention: This software (modified or not) and binary are used for
|
||||
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||
*******************************************************************************/
|
||||
#ifndef __SYSTEM_CH32X035_H
|
||||
#define __SYSTEM_CH32X035_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HCLK_48MHZ RCC_HPRE_DIV1
|
||||
#define HCLK_24MHZ RCC_HPRE_DIV2
|
||||
#define HCLK_16MHZ RCC_HPRE_DIV3
|
||||
#define HCLK_12MHZ RCC_HPRE_DIV4
|
||||
#define HCLK_9_6MHZ RCC_HPRE_DIV5
|
||||
#define HCLK_8MHZ RCC_HPRE_DIV6
|
||||
#define HCLK_6_8MHZ RCC_HPRE_DIV7
|
||||
#define HCLK_6MHZ RCC_HPRE_DIV8
|
||||
#define HCLK_3MHZ RCC_HPRE_DIV16
|
||||
#define HCLK_1_5MHZ RCC_HPRE_DIV32
|
||||
#define HCLK_750KHZ RCC_HPRE_DIV64
|
||||
#define HCLK_375KHZ RCC_HPRE_DIV128
|
||||
#define HCLK_187KHZ RCC_HPRE_DIV256
|
||||
|
||||
|
||||
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
|
||||
|
||||
/* System_Exported_Functions */
|
||||
extern void SystemInit(void);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
|
||||
void SetSysClock_HSI(uint32_t divider);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
6
firmware/app/ui/btn.c
Normal file
6
firmware/app/ui/btn.c
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* btn.c: handler for user interface with real or capacitive buttons
|
||||
*/
|
||||
|
||||
#include "ch32x035_conf.h"
|
||||
#include "driver/adc.h"
|
||||
Reference in New Issue
Block a user