Practice60 RGB and PWM Backlight (#4929)
* Update Practice60 to enable RGB via SPI DMA and use PWM backlight breathing * Correct stm32f103c8t6 flash size in eeprom definition * Remove unused files and improve ifdef checks * Update quantum/rgblight.c Co-Authored-By: awkannan <andrew.kannan@klaviyo.com> * Update quantum/rgblight.c Co-Authored-By: awkannan <andrew.kannan@klaviyo.com> * EEPROM implementation fix and updated p60 code * Update define * Remove dead code * Update keymap to remove test key * Update keymap againmaster
parent
d9120412d3
commit
0f507f0169
|
@ -128,11 +128,11 @@ unsigned char I2C_Write(unsigned char c)
|
||||||
c <<= 1;
|
c <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
I2C_WriteBit(0);
|
I2C_WriteBit(0);
|
||||||
_delay_us(I2C_DELAY);
|
_delay_us(I2C_DELAY);
|
||||||
_delay_us(I2C_DELAY);
|
_delay_us(I2C_DELAY);
|
||||||
|
|
||||||
// _delay_us(I2C_DELAY);
|
// _delay_us(I2C_DELAY);
|
||||||
//return I2C_ReadBit();
|
//return I2C_ReadBit();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -7,4 +7,4 @@
|
||||||
|
|
||||||
// STM32F103* does NOT have an USB bootloader in ROM (only serial),
|
// STM32F103* does NOT have an USB bootloader in ROM (only serial),
|
||||||
// so setting anything here does not make much sense
|
// so setting anything here does not make much sense
|
||||||
// #define STM32_BOOTLOADER_ADDRESS 0x1FFFC800
|
#define STM32_BOOTLOADER_ADDRESS 0x80000000
|
||||||
|
|
|
@ -35,7 +35,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#define MATRIX_ROW_PINS { B3, B4, B5, B6, B7 }
|
#define MATRIX_ROW_PINS { B3, B4, B5, B6, B7 }
|
||||||
#define DIODE_DIRECTION COL2ROW
|
#define DIODE_DIRECTION COL2ROW
|
||||||
|
|
||||||
#define BACKLIGHT_LEVELS 1
|
#define BACKLIGHT_LEVELS 6
|
||||||
|
#define BACKLIGHT_BREATHING
|
||||||
|
#define BREATHING_PERIOD 6
|
||||||
|
|
||||||
/* define if matrix has ghost */
|
/* define if matrix has ghost */
|
||||||
//#define MATRIX_HAS_GHOST
|
//#define MATRIX_HAS_GHOST
|
||||||
|
@ -48,6 +50,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
/* Locking resynchronize hack */
|
/* Locking resynchronize hack */
|
||||||
#define LOCKING_RESYNC_ENABLE
|
#define LOCKING_RESYNC_ENABLE
|
||||||
|
|
||||||
|
#define RGBLIGHT_ANIMATIONS
|
||||||
|
|
||||||
|
#define WS2812_LED_N 9
|
||||||
|
#define RGBLED_NUM WS2812_LED_N
|
||||||
|
#define PORT_WS2812 GPIOB
|
||||||
|
#define PIN_WS2812 15
|
||||||
|
#define WS2812_SPI SPID2
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Feature disable options
|
* Feature disable options
|
||||||
* These options are also useful to firmware size reduction.
|
* These options are also useful to firmware size reduction.
|
||||||
|
|
|
@ -111,7 +111,7 @@
|
||||||
* @brief Enables the PWM subsystem.
|
* @brief Enables the PWM subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_PWM FALSE
|
#define HAL_USE_PWM TRUE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
/* hsv2rgb.c
|
|
||||||
* Integer only conversion functions between HSV and RGB
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hsv2rgb.h"
|
|
||||||
|
|
||||||
// TODO fix these buggy macros
|
|
||||||
#define max(x,y) ((x>y) ? x:y)
|
|
||||||
#define min(x,y) ((x>y) ? y:x)
|
|
||||||
#define min3(x,y,z) (min(min(x,y),z))
|
|
||||||
#define max3(x,y,z) (max(max(x,y),z))
|
|
||||||
|
|
||||||
|
|
||||||
rgb_color hsv2rgb(hsv_color hsv)
|
|
||||||
{
|
|
||||||
// From : http://qscribble.blogspot.fr/2008/06/integer-conversion-from-hsl-to-rgb.html
|
|
||||||
int h = hsv.h;
|
|
||||||
int s = hsv.s;
|
|
||||||
int v = hsv.v;
|
|
||||||
rgb_color rgb = {0, 0, 0};
|
|
||||||
|
|
||||||
if (v == 0)
|
|
||||||
return rgb;
|
|
||||||
|
|
||||||
// sextant = 0 .. 5
|
|
||||||
int sextant = (h*6)/256;
|
|
||||||
// f = 0 .. 42
|
|
||||||
int f = h - (sextant*256)/6;
|
|
||||||
|
|
||||||
int p = (v * (256 - s))/256;
|
|
||||||
int q = (v * (256*43 - s*f))/(256*43);
|
|
||||||
int t = (v * (256*43 - s*(43-f)))/(256*43);
|
|
||||||
|
|
||||||
// Corrige les erreurs dues aux arrondis
|
|
||||||
p = max(min(p, 255), 0);
|
|
||||||
q = max(min(q, 255), 0);
|
|
||||||
t = max(min(t, 255), 0);
|
|
||||||
|
|
||||||
switch(sextant){
|
|
||||||
case 0: rgb.r = v; rgb.g = t; rgb.b = p; break;
|
|
||||||
case 1: rgb.r = q; rgb.g = v; rgb.b = p; break;
|
|
||||||
case 2: rgb.r = p; rgb.g = v; rgb.b = t; break;
|
|
||||||
case 3: rgb.r = p; rgb.g = q; rgb.b = v; break;
|
|
||||||
case 4: rgb.r = t; rgb.g = p; rgb.b = v; break;
|
|
||||||
default:rgb.r = v; rgb.g = p; rgb.b = q; break;
|
|
||||||
}
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
hsv_color rgb2hsv(rgb_color rgb)
|
|
||||||
{
|
|
||||||
// From : http://www.ruinelli.ch/rgb-to-hsv
|
|
||||||
hsv_color hsv = {0, 0, 0};
|
|
||||||
int min, max, delta;
|
|
||||||
|
|
||||||
min = min3(rgb.r, rgb.g, rgb.b);
|
|
||||||
max = max3(rgb.r, rgb.g, rgb.b);
|
|
||||||
|
|
||||||
if(max==0) {
|
|
||||||
hsv.h = 0;
|
|
||||||
hsv.s = 0;
|
|
||||||
hsv.v = 0;
|
|
||||||
return hsv;
|
|
||||||
}
|
|
||||||
|
|
||||||
hsv.v = max;
|
|
||||||
delta = max - min;
|
|
||||||
|
|
||||||
hsv.s = (delta)*255 / max;
|
|
||||||
|
|
||||||
if(rgb.r == max)
|
|
||||||
hsv.h = (rgb.g - rgb.b)*42/delta; // between yellow & magenta
|
|
||||||
else if(rgb.g == max)
|
|
||||||
hsv.h = 120 + (rgb.b - rgb.r)*42/delta; // between cyan & yellow
|
|
||||||
else
|
|
||||||
hsv.h = 240 + (rgb.r - rgb.g)*42/delta; // between magenta & cyan
|
|
||||||
|
|
||||||
return hsv;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
/* hsv2rgb.h
|
|
||||||
* Convert Hue Saturation Value to Red Green Blue
|
|
||||||
*
|
|
||||||
* Programme de convertion d'une information HSV en RGB
|
|
||||||
*/
|
|
||||||
#ifndef HSV2RGB_H
|
|
||||||
#define HSV2RGB_H
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char h;
|
|
||||||
unsigned char s;
|
|
||||||
unsigned char v;
|
|
||||||
} hsv_color;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char r;
|
|
||||||
unsigned char g;
|
|
||||||
unsigned char b;
|
|
||||||
} rgb_color;
|
|
||||||
|
|
||||||
rgb_color hsv2rgb(hsv_color hsv);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -32,16 +32,16 @@ enum custom_keycodes {
|
||||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
[_BASE] = LAYOUT_60_ansi(
|
[_BASE] = LAYOUT_60_ansi(
|
||||||
KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, \
|
KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, \
|
||||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, MT(MOD_LSFT, KC_Y), KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, \
|
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, \
|
||||||
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, \
|
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, \
|
||||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, \
|
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, \
|
||||||
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RGUI, MO(_FN1), KC_RCTL
|
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RGUI, MO(_FN1), KC_RCTL
|
||||||
),
|
),
|
||||||
|
|
||||||
[_FN1] = LAYOUT_60_ansi(
|
[_FN1] = LAYOUT_60_ansi(
|
||||||
KC_GESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_BSPC, \
|
KC_GESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, \
|
||||||
RGB_TOG, RGB_MOD, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
RGB_TOG, RGB_MOD, KC_UP, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
_______, KC_LEFT, KC_DOWN, KC_RGHT, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
BL_BRTG, KC_LEFT, KC_DOWN, KC_RGHT, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
BL_INC, BL_DEC, BL_TOGG, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
BL_INC, BL_DEC, BL_TOGG, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
|
||||||
KC_GRV, _______, _______, _______, _______, _______, _______, _______
|
KC_GRV, _______, _______, _______, _______, _______, _______, _______
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,34 +18,240 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
#include "backlight.h"
|
#include "backlight.h"
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
#include "led_custom.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
|
|
||||||
|
static void breathing_callback(PWMDriver *pwmp);
|
||||||
|
|
||||||
|
static PWMConfig pwmCFG = {
|
||||||
|
0xFFFF, /* PWM clock frequency */
|
||||||
|
256, /* PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
|
||||||
|
NULL, /* No Callback */
|
||||||
|
{
|
||||||
|
{PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* Enable Channel 0 */
|
||||||
|
{PWM_OUTPUT_DISABLED, NULL},
|
||||||
|
{PWM_OUTPUT_DISABLED, NULL},
|
||||||
|
{PWM_OUTPUT_DISABLED, NULL}
|
||||||
|
},
|
||||||
|
0, /* HW dependent part.*/
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static PWMConfig pwmCFG_breathing = {
|
||||||
|
0xFFFF, /* 10kHz PWM clock frequency */
|
||||||
|
256, /* PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
|
||||||
|
breathing_callback, /* Breathing Callback */
|
||||||
|
{
|
||||||
|
{PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* Enable Channel 0 */
|
||||||
|
{PWM_OUTPUT_DISABLED, NULL},
|
||||||
|
{PWM_OUTPUT_DISABLED, NULL},
|
||||||
|
{PWM_OUTPUT_DISABLED, NULL}
|
||||||
|
},
|
||||||
|
0, /* HW dependent part.*/
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
// See http://jared.geek.nz/2013/feb/linear-led-pwm
|
||||||
|
static uint16_t cie_lightness(uint16_t v) {
|
||||||
|
if (v <= 5243) // if below 8% of max
|
||||||
|
return v / 9; // same as dividing by 900%
|
||||||
|
else {
|
||||||
|
uint32_t y = (((uint32_t) v + 10486) << 8) / (10486 + 0xFFFFUL); // add 16% of max and compare
|
||||||
|
// to get a useful result with integer division, we shift left in the expression above
|
||||||
|
// and revert what we've done again after squaring.
|
||||||
|
y = y * y * y >> 8;
|
||||||
|
if (y > 0xFFFFUL) // prevent overflow
|
||||||
|
return 0xFFFFU;
|
||||||
|
else
|
||||||
|
return (uint16_t) y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void backlight_init_ports(void) {
|
void backlight_init_ports(void) {
|
||||||
printf("backlight_init_ports()\n");
|
printf("backlight_init_ports()\n");
|
||||||
#ifdef BACKLIGHT_ENABLE
|
#ifdef BACKLIGHT_ENABLE
|
||||||
palSetPadMode(GPIOA, 8, PAL_MODE_OUTPUT_PUSHPULL);
|
|
||||||
palSetPad(GPIOA, 8);
|
palSetPadMode(GPIOA, 8, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
|
||||||
|
pwmStart(&PWMD1, &pwmCFG);
|
||||||
|
pwmEnableChannel(&PWMD1, 0, PWM_FRACTION_TO_WIDTH(&PWMD1, 0xFFFF,cie_lightness(0xFFFF)));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void backlight_set(uint8_t level) {
|
void backlight_set(uint8_t level) {
|
||||||
printf("backlight_set(%d)\n", level);
|
printf("backlight_set(%d)\n", level);
|
||||||
#ifdef BACKLIGHT_ENABLE
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
uint32_t duty = (uint32_t)(cie_lightness(0xFFFF * (uint32_t) level / BACKLIGHT_LEVELS));
|
||||||
|
printf("duty: (%d)\n", duty);
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
// Turn backlight off
|
// Turn backlight off
|
||||||
palSetPad(GPIOA, 8);
|
pwmDisableChannel(&PWMD1, 0);
|
||||||
} else {
|
} else {
|
||||||
// Turn backlight on
|
// Turn backlight on
|
||||||
palClearPad(GPIOA, 8);
|
if(!is_breathing()){
|
||||||
|
pwmEnableChannel(&PWMD1, 0, PWM_FRACTION_TO_WIDTH(&PWMD1,0xFFFF,duty));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t backlight_tick = 0;
|
||||||
|
|
||||||
|
void backlight_task(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BREATHING_NO_HALT 0
|
||||||
|
#define BREATHING_HALT_OFF 1
|
||||||
|
#define BREATHING_HALT_ON 2
|
||||||
|
#define BREATHING_STEPS 128
|
||||||
|
|
||||||
|
static uint8_t breathing_period = BREATHING_PERIOD;
|
||||||
|
static uint8_t breathing_halt = BREATHING_NO_HALT;
|
||||||
|
static uint16_t breathing_counter = 0;
|
||||||
|
|
||||||
|
bool is_breathing(void) {
|
||||||
|
return PWMD1.config == &pwmCFG_breathing;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define breathing_min() do {breathing_counter = 0;} while (0)
|
||||||
|
#define breathing_max() do {breathing_counter = breathing_period * 256 / 2;} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
void breathing_interrupt_enable(void){
|
||||||
|
pwmStop(&PWMD1);
|
||||||
|
printf("starting with callback\n");
|
||||||
|
pwmStart(&PWMD1, &pwmCFG_breathing);
|
||||||
|
chSysLockFromISR();
|
||||||
|
pwmEnablePeriodicNotification(&PWMD1);
|
||||||
|
pwmEnableChannelI(
|
||||||
|
&PWMD1,
|
||||||
|
0,
|
||||||
|
PWM_FRACTION_TO_WIDTH(
|
||||||
|
&PWMD1,
|
||||||
|
0xFFFF,
|
||||||
|
0xFFFF
|
||||||
|
)
|
||||||
|
);
|
||||||
|
chSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_interrupt_disable(void){
|
||||||
|
pwmStop(&PWMD1);
|
||||||
|
printf("starting without callback\n");
|
||||||
|
pwmStart(&PWMD1, &pwmCFG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_enable(void)
|
||||||
|
{
|
||||||
|
printf("breathing_enable()\n");
|
||||||
|
breathing_counter = 0;
|
||||||
|
breathing_halt = BREATHING_NO_HALT;
|
||||||
|
breathing_interrupt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_pulse(void)
|
||||||
|
{
|
||||||
|
if (get_backlight_level() == 0)
|
||||||
|
breathing_min();
|
||||||
|
else
|
||||||
|
breathing_max();
|
||||||
|
breathing_halt = BREATHING_HALT_ON;
|
||||||
|
breathing_interrupt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_disable(void)
|
||||||
|
{
|
||||||
|
printf("breathing_disable()\n");
|
||||||
|
breathing_interrupt_disable();
|
||||||
|
// Restore backlight level
|
||||||
|
backlight_set(get_backlight_level());
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_self_disable(void)
|
||||||
|
{
|
||||||
|
if (get_backlight_level() == 0)
|
||||||
|
breathing_halt = BREATHING_HALT_OFF;
|
||||||
|
else
|
||||||
|
breathing_halt = BREATHING_HALT_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_toggle(void) {
|
||||||
|
if (is_breathing()){
|
||||||
|
printf("disable breathing\n");
|
||||||
|
breathing_disable();
|
||||||
|
} else {
|
||||||
|
printf("enable breathing\n");
|
||||||
|
breathing_enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_period_set(uint8_t value)
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
value = 1;
|
||||||
|
breathing_period = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_period_default(void) {
|
||||||
|
breathing_period_set(BREATHING_PERIOD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_period_inc(void)
|
||||||
|
{
|
||||||
|
breathing_period_set(breathing_period+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void breathing_period_dec(void)
|
||||||
|
{
|
||||||
|
breathing_period_set(breathing_period-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To generate breathing curve in python:
|
||||||
|
* from math import sin, pi; [int(sin(x/128.0*pi)**4*255) for x in range(128)]
|
||||||
|
*/
|
||||||
|
static const uint8_t breathing_table[BREATHING_STEPS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 17, 20, 24, 28, 32, 36, 41, 46, 51, 57, 63, 70, 76, 83, 91, 98, 106, 113, 121, 129, 138, 146, 154, 162, 170, 178, 185, 193, 200, 207, 213, 220, 225, 231, 235, 240, 244, 247, 250, 252, 253, 254, 255, 254, 253, 252, 250, 247, 244, 240, 235, 231, 225, 220, 213, 207, 200, 193, 185, 178, 170, 162, 154, 146, 138, 129, 121, 113, 106, 98, 91, 83, 76, 70, 63, 57, 51, 46, 41, 36, 32, 28, 24, 20, 17, 15, 12, 10, 8, 6, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
// Use this before the cie_lightness function.
|
||||||
|
static inline uint16_t scale_backlight(uint16_t v) {
|
||||||
|
return v / BACKLIGHT_LEVELS * get_backlight_level();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void breathing_callback(PWMDriver *pwmp)
|
||||||
|
{
|
||||||
|
(void)pwmp;
|
||||||
|
uint16_t interval = (uint16_t) breathing_period * 256 / BREATHING_STEPS;
|
||||||
|
// resetting after one period to prevent ugly reset at overflow.
|
||||||
|
breathing_counter = (breathing_counter + 1) % (breathing_period * 256);
|
||||||
|
uint8_t index = breathing_counter / interval % BREATHING_STEPS;
|
||||||
|
|
||||||
|
if (((breathing_halt == BREATHING_HALT_ON) && (index == BREATHING_STEPS / 2)) ||
|
||||||
|
((breathing_halt == BREATHING_HALT_OFF) && (index == BREATHING_STEPS - 1)))
|
||||||
|
{
|
||||||
|
breathing_interrupt_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t duty = cie_lightness(scale_backlight(breathing_table[index] * 256));
|
||||||
|
|
||||||
|
chSysLockFromISR();
|
||||||
|
pwmEnableChannelI(
|
||||||
|
&PWMD1,
|
||||||
|
0,
|
||||||
|
PWM_FRACTION_TO_WIDTH(
|
||||||
|
&PWMD1,
|
||||||
|
0xFFFF,
|
||||||
|
duty
|
||||||
|
)
|
||||||
|
);
|
||||||
|
chSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void led_set(uint8_t usb_led)
|
void led_set(uint8_t usb_led)
|
||||||
{
|
{
|
||||||
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
|
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
|
||||||
palClearPad(GPIOC, 13);
|
palSetPad(GPIOC, 13);
|
||||||
} else {
|
} else {
|
||||||
palSetPad(GPIOC, 13);
|
palClearPad(GPIOC, 13);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void backlight_task(void);
|
||||||
|
void breathing_interrupt_disable(void);
|
||||||
|
void breathing_interrupt_enable(void);
|
||||||
|
bool is_breathing(void);
|
|
@ -132,7 +132,7 @@
|
||||||
* PWM driver system settings.
|
* PWM driver system settings.
|
||||||
*/
|
*/
|
||||||
#define STM32_PWM_USE_ADVANCED FALSE
|
#define STM32_PWM_USE_ADVANCED FALSE
|
||||||
#define STM32_PWM_USE_TIM1 FALSE
|
#define STM32_PWM_USE_TIM1 TRUE
|
||||||
#define STM32_PWM_USE_TIM2 FALSE
|
#define STM32_PWM_USE_TIM2 FALSE
|
||||||
#define STM32_PWM_USE_TIM3 FALSE
|
#define STM32_PWM_USE_TIM3 FALSE
|
||||||
#define STM32_PWM_USE_TIM4 FALSE
|
#define STM32_PWM_USE_TIM4 FALSE
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
|
|
||||||
#include "ch.h"
|
#include "ch.h"
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
|
#include "led_custom.h"
|
||||||
#include "underglow.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -19,14 +18,18 @@
|
||||||
void matrix_init_kb(void){
|
void matrix_init_kb(void){
|
||||||
/* MOSI pin*/
|
/* MOSI pin*/
|
||||||
palSetPadMode(GPIOB, 15, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
|
palSetPadMode(GPIOB, 15, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
|
||||||
|
|
||||||
LED_ON();
|
LED_ON();
|
||||||
palSetPad(GPIOA, 8);
|
|
||||||
wait_ms(500);
|
wait_ms(500);
|
||||||
palClearPad(GPIOA, 8);
|
|
||||||
LED_OFF();
|
LED_OFF();
|
||||||
|
|
||||||
|
#ifdef RGBLIGHT_ENABLE
|
||||||
leds_init();
|
leds_init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_scan_kb(void)
|
||||||
|
{
|
||||||
|
#ifdef RGBLIGHT_ENABLE
|
||||||
|
rgblight_task();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# project specific files
|
# project specific files
|
||||||
SRC = led.c \
|
SRC = led.c \
|
||||||
underglow.c \
|
ws2812.c
|
||||||
hsv2rgb.c
|
|
||||||
|
|
||||||
# GENERIC STM32F103C8T6 board - stm32duino bootloader
|
# GENERIC STM32F103C8T6 board - stm32duino bootloader
|
||||||
OPT_DEFS = -DCORTEX_VTOR_INIT=0x2000
|
OPT_DEFS = -DCORTEX_VTOR_INIT=0x2000
|
||||||
|
@ -50,6 +49,7 @@ COMMAND_ENABLE = yes # Commands for debug and configuration
|
||||||
SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
|
SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
|
||||||
NKRO_ENABLE = yes # USB Nkey Rollover
|
NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
BACKLIGHT_ENABLE = yes
|
BACKLIGHT_ENABLE = yes
|
||||||
|
RGBLIGHT_ENABLE = yes
|
||||||
|
|
||||||
LAYOUTS = 60_ansi
|
LAYOUTS = 60_ansi
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "hsv2rgb.h"
|
|
||||||
|
|
||||||
void set_leds_color_hsv(hsv_color color);
|
|
||||||
void set_leds_color_rgb(rgb_color color);
|
|
||||||
void set_led_color_hsv(hsv_color color, int pos);
|
|
||||||
void set_led_color_rgb(rgb_color color, int pos);
|
|
||||||
|
|
||||||
void leds_init(void);
|
|
|
@ -1,8 +1,12 @@
|
||||||
#include "ch.h"
|
/*
|
||||||
#include "hal.h"
|
* LEDDriver.c
|
||||||
|
*
|
||||||
|
* Created on: Aug 26, 2013
|
||||||
|
* Author: Omri Iluz
|
||||||
|
*/
|
||||||
|
|
||||||
#include "hsv2rgb.h"
|
#include "ws2812.h"
|
||||||
#include "underglow.h"
|
#include "stdlib.h"
|
||||||
|
|
||||||
#define BYTES_FOR_LED_BYTE 4
|
#define BYTES_FOR_LED_BYTE 4
|
||||||
#define NB_COLORS 3
|
#define NB_COLORS 3
|
||||||
|
@ -10,18 +14,17 @@
|
||||||
#define DATA_SIZE BYTES_FOR_LED*NB_LEDS
|
#define DATA_SIZE BYTES_FOR_LED*NB_LEDS
|
||||||
#define RESET_SIZE 200
|
#define RESET_SIZE 200
|
||||||
#define PREAMBLE_SIZE 4
|
#define PREAMBLE_SIZE 4
|
||||||
|
|
||||||
// Define the spi your LEDs are plugged to here
|
// Define the spi your LEDs are plugged to here
|
||||||
#define LEDS_SPI SPID2
|
#define WS2812_SPI SPID2
|
||||||
// Define the number of LEDs you wish to control in your LED strip
|
// Define the number of LEDs you wish to control in your LED strip
|
||||||
#define NB_LEDS 8
|
#define NB_LEDS RGBLED_NUM
|
||||||
|
|
||||||
#define LED_SPIRAL 1
|
#define LED_SPIRAL 1
|
||||||
|
|
||||||
static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE];
|
static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE];
|
||||||
static uint8_t get_protocol_eq(uint8_t data, int pos);
|
static uint8_t get_protocol_eq(uint8_t data, int pos);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This lib is meant to be used asynchronously, thus the colors contained in
|
* This lib is meant to be used asynchronously, thus the colors contained in
|
||||||
* the txbuf will be sent in loop, so that the colors are always the ones you
|
* the txbuf will be sent in loop, so that the colors are always the ones you
|
||||||
* put in the table (the user thus have less to worry about)
|
* put in the table (the user thus have less to worry about)
|
||||||
|
@ -37,38 +40,18 @@ static THD_WORKING_AREA(LEDS_THREAD_WA, 128);
|
||||||
static THD_FUNCTION(ledsThread, arg) {
|
static THD_FUNCTION(ledsThread, arg) {
|
||||||
(void) arg;
|
(void) arg;
|
||||||
while(1){
|
while(1){
|
||||||
spiSend(&LEDS_SPI, PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE, txbuf);
|
spiSend(&WS2812_SPI, PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE, txbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LED_SPIRAL
|
static const SPIConfig spicfg = {
|
||||||
/*
|
|
||||||
* 'Led spiral' is a simple demo in which we put all the leds to the same
|
|
||||||
* color, where this color does all the hsv circle in loop.
|
|
||||||
* If you want to launch the thread that will chage the led colors to the
|
|
||||||
* appropriate value, simply set LED_SPIRAL to 1.
|
|
||||||
*/
|
|
||||||
static THD_WORKING_AREA(HSVTRANS_WA, 128);
|
|
||||||
static THD_FUNCTION(hsv_transThread, arg){
|
|
||||||
(void) arg;
|
|
||||||
hsv_color color = {0, 255, 127};
|
|
||||||
while(1){
|
|
||||||
color.h += 1;
|
|
||||||
color.h %= 256;
|
|
||||||
set_leds_color_hsv(color);
|
|
||||||
chThdSleepMilliseconds(50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const SPIConfig spicfg = {
|
|
||||||
NULL,
|
NULL,
|
||||||
GPIOB,
|
PORT_WS2812,
|
||||||
15,
|
PIN_WS2812,
|
||||||
SPI_CR1_BR_1|SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us
|
SPI_CR1_BR_1|SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function used to initialize the driver.
|
* Function used to initialize the driver.
|
||||||
*
|
*
|
||||||
* Starts by shutting off all the LEDs.
|
* Starts by shutting off all the LEDs.
|
||||||
|
@ -77,21 +60,19 @@ static const SPIConfig spicfg = {
|
||||||
* txbuff values)
|
* txbuff values)
|
||||||
*/
|
*/
|
||||||
void leds_init(void){
|
void leds_init(void){
|
||||||
|
/* MOSI pin*/
|
||||||
|
palSetPadMode(PORT_WS2812, PIN_WS2812, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
|
||||||
for(int i = 0; i < RESET_SIZE; i++)
|
for(int i = 0; i < RESET_SIZE; i++)
|
||||||
txbuf[DATA_SIZE+i] = 0x00;
|
txbuf[DATA_SIZE+i] = 0x00;
|
||||||
for (int i=0; i<PREAMBLE_SIZE; i++)
|
for (int i=0; i<PREAMBLE_SIZE; i++)
|
||||||
txbuf[i] = 0x00;
|
txbuf[i] = 0x00;
|
||||||
spiAcquireBus(&LEDS_SPI); /* Acquire ownership of the bus. */
|
spiAcquireBus(&WS2812_SPI); /* Acquire ownership of the bus. */
|
||||||
spiStart(&LEDS_SPI, &spicfg); /* Setup transfer parameters. */
|
spiStart(&WS2812_SPI, &spicfg); /* Setup transfer parameters. */
|
||||||
spiSelect(&LEDS_SPI); /* Slave Select assertion. */
|
spiSelect(&WS2812_SPI); /* Slave Select assertion. */
|
||||||
chThdCreateStatic(LEDS_THREAD_WA, sizeof(LEDS_THREAD_WA),NORMALPRIO, ledsThread, NULL);
|
chThdCreateStatic(LEDS_THREAD_WA, sizeof(LEDS_THREAD_WA),NORMALPRIO, ledsThread, NULL);
|
||||||
#if LED_SPIRAL
|
|
||||||
chThdCreateStatic(HSVTRANS_WA, sizeof(HSVTRANS_WA),
|
|
||||||
NORMALPRIO, hsv_transThread, NULL);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As the trick here is to use the SPI to send a huge pattern of 0 and 1 to
|
* As the trick here is to use the SPI to send a huge pattern of 0 and 1 to
|
||||||
* the ws2812b protocol, we use this helper function to translate bytes into
|
* the ws2812b protocol, we use this helper function to translate bytes into
|
||||||
* 0s and 1s for the LED (with the appropriate timing).
|
* 0s and 1s for the LED (with the appropriate timing).
|
||||||
|
@ -109,20 +90,20 @@ static uint8_t get_protocol_eq(uint8_t data, int pos){
|
||||||
return eq;
|
return eq;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If you want to set a LED's color in the HSV color space, simply call this
|
void WS2812_init(void) {
|
||||||
* function with a hsv_color containing the desired color and the index of the
|
leds_init();
|
||||||
* led on the LED strip (starting from 0, the first one being the closest the
|
|
||||||
* first plugged to the board)
|
|
||||||
*
|
|
||||||
* Only set the color of the LEDs through the functions given by this API
|
|
||||||
* (unless you really know what you are doing)
|
|
||||||
*/
|
|
||||||
void set_led_color_hsv(hsv_color color, int pos){
|
|
||||||
set_led_color_rgb(hsv2rgb(color), pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds) {
|
||||||
|
uint8_t i = 0;
|
||||||
|
while (i < number_of_leds) {
|
||||||
|
set_led_color_rgb(ledarray[i], i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
* If you want to set a LED's color in the RGB color space, simply call this
|
* If you want to set a LED's color in the RGB color space, simply call this
|
||||||
* function with a hsv_color containing the desired color and the index of the
|
* function with a hsv_color containing the desired color and the index of the
|
||||||
* led on the LED strip (starting from 0, the first one being the closest the
|
* led on the LED strip (starting from 0, the first one being the closest the
|
||||||
|
@ -131,7 +112,7 @@ void set_led_color_hsv(hsv_color color, int pos){
|
||||||
* Only set the color of the LEDs through the functions given by this API
|
* Only set the color of the LEDs through the functions given by this API
|
||||||
* (unless you really know what you are doing)
|
* (unless you really know what you are doing)
|
||||||
*/
|
*/
|
||||||
void set_led_color_rgb(rgb_color color, int pos){
|
void set_led_color_rgb(LED_TYPE color, int pos){
|
||||||
for(int j = 0; j < 4; j++)
|
for(int j = 0; j < 4; j++)
|
||||||
txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + j] = get_protocol_eq(color.g, j);
|
txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + j] = get_protocol_eq(color.g, j);
|
||||||
for(int j = 0; j < 4; j++)
|
for(int j = 0; j < 4; j++)
|
||||||
|
@ -140,18 +121,12 @@ void set_led_color_rgb(rgb_color color, int pos){
|
||||||
txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE*2+j] = get_protocol_eq(color.b, j);
|
txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE*2+j] = get_protocol_eq(color.b, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void set_leds_color_rgb(LED_TYPE color){
|
||||||
* Same as the two above, but sets all the LEDs in the LED strip (HSV)
|
|
||||||
*/
|
|
||||||
void set_leds_color_hsv(hsv_color color){
|
|
||||||
for(int i = 0; i < NB_LEDS; i++)
|
|
||||||
set_led_color_hsv(color, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Same as the two above, but sets all the LEDs in the LED strip (RGB)
|
|
||||||
*/
|
|
||||||
void set_leds_color_rgb(rgb_color color){
|
|
||||||
for(int i = 0; i < NB_LEDS; i++)
|
for(int i = 0; i < NB_LEDS; i++)
|
||||||
set_led_color_rgb(color, i);
|
set_led_color_rgb(color, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds) {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "rgblight_types.h"
|
||||||
|
|
||||||
|
|
||||||
|
void set_leds_color_rgb(LED_TYPE color);
|
||||||
|
void set_led_color_rgb(LED_TYPE color, int pos);
|
||||||
|
void leds_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
// This is what users will use to interface with this
|
||||||
|
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds);
|
||||||
|
void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds);
|
||||||
|
|
||||||
|
|
||||||
|
void WS2812_init(void);
|
||||||
|
void WS2812_set_color( uint8_t index, uint8_t red, uint8_t green, uint8_t blue );
|
||||||
|
void WS2812_set_color_all( uint8_t red, uint8_t green, uint8_t blue );
|
||||||
|
void WS2812_send_colors(void);
|
|
@ -19,6 +19,11 @@
|
||||||
#include <avr/eeprom.h>
|
#include <avr/eeprom.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef STM32_EEPROM_ENABLE
|
||||||
|
#include "hal.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
#include "eeprom_stm32.h"
|
||||||
|
#endif
|
||||||
#include "wait.h"
|
#include "wait.h"
|
||||||
#include "progmem.h"
|
#include "progmem.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
@ -120,14 +125,14 @@ void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) {
|
||||||
|
|
||||||
|
|
||||||
uint32_t eeconfig_read_rgblight(void) {
|
uint32_t eeconfig_read_rgblight(void) {
|
||||||
#ifdef __AVR__
|
#if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
|
||||||
return eeprom_read_dword(EECONFIG_RGBLIGHT);
|
return eeprom_read_dword(EECONFIG_RGBLIGHT);
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void eeconfig_update_rgblight(uint32_t val) {
|
void eeconfig_update_rgblight(uint32_t val) {
|
||||||
#ifdef __AVR__
|
#if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
|
||||||
if (eeconfig_read_rgblight() != val) {
|
if (eeconfig_read_rgblight() != val) {
|
||||||
eeprom_update_dword(EECONFIG_RGBLIGHT, val);
|
eeprom_update_dword(EECONFIG_RGBLIGHT, val);
|
||||||
}
|
}
|
||||||
|
@ -333,7 +338,7 @@ void rgblight_disable_noeeprom(void) {
|
||||||
#ifdef RGBLIGHT_USE_TIMER
|
#ifdef RGBLIGHT_USE_TIMER
|
||||||
rgblight_timer_disable();
|
rgblight_timer_disable();
|
||||||
#endif
|
#endif
|
||||||
_delay_ms(50);
|
wait_ms(50);
|
||||||
rgblight_set();
|
rgblight_set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,17 +75,13 @@ uint16_t EEPROM_WriteDataByte (uint16_t Address, uint8_t DataByte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate which page is affected (Pagenum1/Pagenum2...PagenumN)
|
// calculate which page is affected (Pagenum1/Pagenum2...PagenumN)
|
||||||
page = (FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address)) & 0x00000FFF;
|
page = FEE_ADDR_OFFSET(Address) / FEE_PAGE_SIZE;
|
||||||
|
|
||||||
if (page % FEE_PAGE_SIZE) page = page + FEE_PAGE_SIZE;
|
|
||||||
page = (page / FEE_PAGE_SIZE) - 1;
|
|
||||||
|
|
||||||
// if current data is 0xFF, the byte is empty, just overwrite with the new one
|
// if current data is 0xFF, the byte is empty, just overwrite with the new one
|
||||||
if ((*(__IO uint16_t*)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))) == FEE_EMPTY_WORD) {
|
if ((*(__IO uint16_t*)(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address))) == FEE_EMPTY_WORD) {
|
||||||
|
|
||||||
FlashStatus = FLASH_ProgramHalfWord(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address), (uint16_t)(0x00FF & DataByte));
|
FlashStatus = FLASH_ProgramHalfWord(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address), (uint16_t)(0x00FF & DataByte));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
|
|
||||||
// Copy Page to a buffer
|
// Copy Page to a buffer
|
||||||
memcpy(DataBuf, (uint8_t*)FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE), FEE_PAGE_SIZE); // !!! Calculate base address for the desired page
|
memcpy(DataBuf, (uint8_t*)FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE), FEE_PAGE_SIZE); // !!! Calculate base address for the desired page
|
||||||
|
@ -96,18 +92,17 @@ uint16_t EEPROM_WriteDataByte (uint16_t Address, uint8_t DataByte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// manipulate desired data byte in temp data array if new byte is differ to the current
|
// manipulate desired data byte in temp data array if new byte is differ to the current
|
||||||
DataBuf[FEE_ADDR_OFFSET(Address)] = DataByte;
|
DataBuf[FEE_ADDR_OFFSET(Address) % FEE_PAGE_SIZE] = DataByte;
|
||||||
|
|
||||||
//Erase Page
|
//Erase Page
|
||||||
FlashStatus = FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + page);
|
FlashStatus = FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE));
|
||||||
|
|
||||||
// Write new data (whole page) to flash if data has beed changed
|
// Write new data (whole page) to flash if data has been changed
|
||||||
for(i = 0; i < (FEE_PAGE_SIZE / 2); i++) {
|
for(i = 0; i < (FEE_PAGE_SIZE / 2); i++) {
|
||||||
if ((__IO uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]) != 0xFFFF) {
|
if ((__IO uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]) != 0xFFFF) {
|
||||||
FlashStatus = FLASH_ProgramHalfWord((FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE)) + (i * 2), (uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]));
|
FlashStatus = FLASH_ProgramHalfWord((FEE_PAGE_BASE_ADDRESS + (page * FEE_PAGE_SIZE)) + (i * 2), (uint16_t)(0xFF00 | DataBuf[FEE_ADDR_OFFSET(i)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return FlashStatus;
|
return FlashStatus;
|
||||||
}
|
}
|
||||||
|
@ -168,7 +163,7 @@ void eeprom_update_word (uint16_t *Address, uint16_t Value)
|
||||||
uint32_t eeprom_read_dword (const uint32_t *Address)
|
uint32_t eeprom_read_dword (const uint32_t *Address)
|
||||||
{
|
{
|
||||||
const uint16_t p = (const uint32_t) Address;
|
const uint16_t p = (const uint32_t) Address;
|
||||||
return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8)
|
return EEPROM_ReadDataByte(p) | (EEPROM_ReadDataByte(p+1) << 8)
|
||||||
| (EEPROM_ReadDataByte(p+2) << 16) | (EEPROM_ReadDataByte(p+3) << 24);
|
| (EEPROM_ReadDataByte(p+2) << 16) | (EEPROM_ReadDataByte(p+3) << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue