]> git.donarmstrong.com Git - qmk_firmware.git/commitdiff
Practice60 RGB and PWM Backlight (#4929)
authorAndrew Kannan <andrew.kannan@klaviyo.com>
Tue, 29 Jan 2019 00:40:02 +0000 (19:40 -0500)
committerDrashna Jaelre <drashna@live.com>
Tue, 29 Jan 2019 00:40:02 +0000 (16:40 -0800)
* 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 again

18 files changed:
drivers/avr/ws2812.c
keyboards/handwired/practice60/bootloader_defs.h
keyboards/handwired/practice60/config.h
keyboards/handwired/practice60/halconf.h
keyboards/handwired/practice60/hsv2rgb.c [deleted file]
keyboards/handwired/practice60/hsv2rgb.h [deleted file]
keyboards/handwired/practice60/keymaps/default/keymap.c
keyboards/handwired/practice60/led.c
keyboards/handwired/practice60/led_custom.h [new file with mode: 0644]
keyboards/handwired/practice60/mcuconf.h
keyboards/handwired/practice60/practice60.c
keyboards/handwired/practice60/rules.mk
keyboards/handwired/practice60/underglow.c [deleted file]
keyboards/handwired/practice60/underglow.h [deleted file]
keyboards/handwired/practice60/ws2812.c [new file with mode: 0644]
keyboards/handwired/practice60/ws2812.h [new file with mode: 0644]
quantum/rgblight.c
tmk_core/common/chibios/eeprom_stm32.c

index 59e032bf71c96a4a653764d98d67acc954a5ded3..5bd837ec7542959a4b5c51491bea2cc49c1810dc 100644 (file)
@@ -128,11 +128,11 @@ unsigned char I2C_Write(unsigned char c)
         c <<= 1;
     }
 
-    
+
     I2C_WriteBit(0);
     _delay_us(I2C_DELAY);
     _delay_us(I2C_DELAY);
-  
+
     // _delay_us(I2C_DELAY);
     //return I2C_ReadBit();
     return 0;
index 0f45203cb61390be06d724976377dff871bda12f..6b8fa9f727c95681d9daf977d592da260c40f06d 100644 (file)
@@ -7,4 +7,4 @@
 
 // STM32F103* does NOT have an USB bootloader in ROM (only serial),
 //  so setting anything here does not make much sense
-// #define STM32_BOOTLOADER_ADDRESS 0x1FFFC800
+#define STM32_BOOTLOADER_ADDRESS 0x80000000
index 648dd62edcf2a53230f0b66aec10809772e4dffe..c015bb74652ea0a643c89644df0abbca47d8e71b 100644 (file)
@@ -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 DIODE_DIRECTION COL2ROW
 
-#define BACKLIGHT_LEVELS 1
+#define BACKLIGHT_LEVELS 6
+#define BACKLIGHT_BREATHING
+#define BREATHING_PERIOD 6
 
 /* define if 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 */
 #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
  *  These options are also useful to firmware size reduction.
index 5fba285a380da4f6db424a2fdc9337fbbdd62975..72879a575b9c61e6d6a97045154c8c0274ac7c7d 100644 (file)
  * @brief   Enables the PWM subsystem.
  */
 #if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
-#define HAL_USE_PWM                 FALSE
+#define HAL_USE_PWM                 TRUE
 #endif
 
 /**
diff --git a/keyboards/handwired/practice60/hsv2rgb.c b/keyboards/handwired/practice60/hsv2rgb.c
deleted file mode 100644 (file)
index adb7af8..0000000
+++ /dev/null
@@ -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;
-}
\ No newline at end of file
diff --git a/keyboards/handwired/practice60/hsv2rgb.h b/keyboards/handwired/practice60/hsv2rgb.h
deleted file mode 100644 (file)
index 99566c3..0000000
+++ /dev/null
@@ -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
\ No newline at end of file
index ac6e755097206c014ff488f451d1a7d4d2a90dde..66ebe0646d5d346d5cf6d8506896999ac91197af 100644 (file)
@@ -32,16 +32,16 @@ enum custom_keycodes {
 const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
   [_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_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_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
   ),
 
   [_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,   _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
-    _______, KC_LEFT, KC_DOWN, KC_RGHT, _______, _______, _______, _______, _______, _______, _______, _______,          _______, \
+    BL_BRTG, KC_LEFT, KC_DOWN, KC_RGHT, _______, _______, _______, _______, _______, _______, _______, _______,          _______, \
     BL_INC,  BL_DEC,  BL_TOGG, _______, _______, _______, _______, _______, _______, _______, _______,                   _______, \
     KC_GRV,  _______, _______,                            _______,                            _______, _______, _______, _______
   )
index f15baed169d4c5817b2be5a8d806b8fa9027c58b..a9ede5bbaa855017173ec1ce619c6526fcd10a52 100644 (file)
@@ -18,34 +18,240 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "hal.h"
 #include "backlight.h"
 #include "led.h"
+#include "led_custom.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) {
     printf("backlight_init_ports()\n");
     #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
 }
 
 void backlight_set(uint8_t level) {
     printf("backlight_set(%d)\n", level);
     #ifdef BACKLIGHT_ENABLE
+    uint32_t duty = (uint32_t)(cie_lightness(0xFFFF * (uint32_t) level / BACKLIGHT_LEVELS));
+    printf("duty: (%d)\n", duty);
     if (level == 0) {
         // Turn backlight off
-        palSetPad(GPIOA, 8);
+        pwmDisableChannel(&PWMD1, 0);
     } else {
-        // Turn backlight on
-        palClearPad(GPIOA, 8);
+      // Turn backlight on
+      if(!is_breathing()){
+        pwmEnableChannel(&PWMD1, 0, PWM_FRACTION_TO_WIDTH(&PWMD1,0xFFFF,duty));
+      }
     }
     #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)
 {
     if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
-        palClearPad(GPIOC, 13);
+      palSetPad(GPIOC, 13);
     } else {
-       palSetPad(GPIOC, 13);
+       palClearPad(GPIOC, 13);
     }
 }
diff --git a/keyboards/handwired/practice60/led_custom.h b/keyboards/handwired/practice60/led_custom.h
new file mode 100644 (file)
index 0000000..8451c06
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+void backlight_task(void);
+void breathing_interrupt_disable(void);
+void breathing_interrupt_enable(void);
+bool is_breathing(void);
index 9945e7408d1281c85dbb6b94196e4bf1d4fbaa95..fced27289e0d8d38b20a3b98794cfb54aac83548 100644 (file)
  * PWM driver system settings.
  */
 #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_TIM3                  FALSE
 #define STM32_PWM_USE_TIM4                  FALSE
index 5d0fffbd09ee5db71c4833cc126c99e7244d146e..acc0f00e530c7509c2510b3ad9d4433a34ba81c7 100644 (file)
@@ -3,8 +3,7 @@
 
 #include "ch.h"
 #include "hal.h"
-
-#include "underglow.h"
+#include "led_custom.h"
 #include "print.h"
 #include "debug.h"
 #include "util.h"
 void matrix_init_kb(void){
       /* MOSI pin*/
     palSetPadMode(GPIOB, 15, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
-
     LED_ON();
-    palSetPad(GPIOA, 8);
     wait_ms(500);
-    palClearPad(GPIOA, 8);
     LED_OFF();
 
+#ifdef RGBLIGHT_ENABLE
     leds_init();
+#endif
+}
 
-
+void matrix_scan_kb(void)
+{
+  #ifdef RGBLIGHT_ENABLE
+    rgblight_task();
+  #endif
 }
index 915b07320c33e18a114866e1d4c72c1c60c55949..e417c91ee87b7db93df4df57e7c659495da3cdec 100644 (file)
@@ -1,7 +1,6 @@
 # project specific files
 SRC =  led.c \
-                 underglow.c \
-                 hsv2rgb.c
+                 ws2812.c
 
 # GENERIC STM32F103C8T6 board - stm32duino bootloader
 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
 NKRO_ENABLE = yes          # USB Nkey Rollover
 BACKLIGHT_ENABLE = yes
+RGBLIGHT_ENABLE = yes
 
 LAYOUTS = 60_ansi
 
diff --git a/keyboards/handwired/practice60/underglow.c b/keyboards/handwired/practice60/underglow.c
deleted file mode 100644 (file)
index 1383af1..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#include "ch.h"
-#include "hal.h"
-
-#include "hsv2rgb.h"
-#include "underglow.h"
-
-#define BYTES_FOR_LED_BYTE 4
-#define NB_COLORS 3
-#define BYTES_FOR_LED BYTES_FOR_LED_BYTE*NB_COLORS
-#define DATA_SIZE BYTES_FOR_LED*NB_LEDS
-#define RESET_SIZE 200
-#define PREAMBLE_SIZE 4
-
-// Define the spi your LEDs are plugged to here
-#define LEDS_SPI SPID2
-// Define the number of LEDs you wish to control in your LED strip
-#define NB_LEDS 8
-
-#define LED_SPIRAL 1
-
-static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE];
-static uint8_t get_protocol_eq(uint8_t data, int pos);
-
-/*
- * 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
- * put in the table (the user thus have less to worry about)
- *
- * Since the data are sent via DMA, and the call to spiSend is a blocking one,
- * the processor ressources are not used to much, if you see your program being
- * too slow, simply add a:
- * chThdSleepMilliseconds(x);
- * after the spiSend, where you increment x untill you are satisfied with your
- * program speed, another trick may be to lower this thread priority : your call
- */
-static THD_WORKING_AREA(LEDS_THREAD_WA, 128);
-static THD_FUNCTION(ledsThread, arg) {
-  (void) arg;
-  while(1){
-    spiSend(&LEDS_SPI, PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE, txbuf);
-  }
-}
-
-#if LED_SPIRAL
-/*
- * '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,
-  GPIOB,
-  15,
-  SPI_CR1_BR_1|SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us
-};
-
-/*
- * Function used to initialize the driver.
- *
- * Starts by shutting off all the LEDs.
- * Then gets access on the LED_SPI driver.
- * May eventually launch an animation on the LEDs (e.g. a thread setting the
- * txbuff values)
- */
-void leds_init(void){
-  for(int i = 0; i < RESET_SIZE; i++)
-    txbuf[DATA_SIZE+i] = 0x00;
-  for (int i=0; i<PREAMBLE_SIZE; i++)
-    txbuf[i] = 0x00;
-  spiAcquireBus(&LEDS_SPI);              /* Acquire ownership of the bus.    */
-  spiStart(&LEDS_SPI, &spicfg);          /* Setup transfer parameters.       */
-  spiSelect(&LEDS_SPI);                  /* Slave Select assertion.          */
-  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
- * the ws2812b protocol, we use this helper function to translate bytes into
- * 0s and 1s for the LED (with the appropriate timing).
- */
-static uint8_t get_protocol_eq(uint8_t data, int pos){
-  uint8_t eq = 0;
-  if (data & (1 << (2*(3-pos))))
-    eq = 0b1110;
-  else
-    eq = 0b1000;
-  if (data & (2 << (2*(3-pos))))
-    eq += 0b11100000;
-  else
-    eq += 0b10000000;
-  return eq;
-}
-
-/*
- * If you want to set a LED's color in the HSV color space, simply call this
- * 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
- * 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);
-}
-
-/*
- * 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
- * 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_rgb(rgb_color color, int pos){
-  for(int j = 0; j < 4; j++)
-    txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + j] = get_protocol_eq(color.g, j);
-  for(int j = 0; j < 4; j++)
-    txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE+j] = get_protocol_eq(color.r, j);
-  for(int j = 0; j < 4; j++)
-    txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE*2+j] = get_protocol_eq(color.b, j);
-}
-
-/*
- * 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++)
-    set_led_color_rgb(color, i);
-}
\ No newline at end of file
diff --git a/keyboards/handwired/practice60/underglow.h b/keyboards/handwired/practice60/underglow.h
deleted file mode 100644 (file)
index ff11952..0000000
+++ /dev/null
@@ -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);
diff --git a/keyboards/handwired/practice60/ws2812.c b/keyboards/handwired/practice60/ws2812.c
new file mode 100644 (file)
index 0000000..7d0f909
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * LEDDriver.c
+ *
+ *  Created on: Aug 26, 2013
+ *      Author: Omri Iluz
+ */
+
+#include "ws2812.h"
+#include "stdlib.h"
+
+#define BYTES_FOR_LED_BYTE 4
+#define NB_COLORS 3
+#define BYTES_FOR_LED BYTES_FOR_LED_BYTE*NB_COLORS
+#define DATA_SIZE BYTES_FOR_LED*NB_LEDS
+#define RESET_SIZE 200
+#define PREAMBLE_SIZE 4
+// Define the spi your LEDs are plugged to here
+#define WS2812_SPI SPID2
+// Define the number of LEDs you wish to control in your LED strip
+#define NB_LEDS RGBLED_NUM
+
+ #define LED_SPIRAL 1
+
+ static uint8_t txbuf[PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE];
+static uint8_t get_protocol_eq(uint8_t data, int pos);
+
+ /*
+ * 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
+ * put in the table (the user thus have less to worry about)
+ *
+ * Since the data are sent via DMA, and the call to spiSend is a blocking one,
+ * the processor ressources are not used to much, if you see your program being
+ * too slow, simply add a:
+ * chThdSleepMilliseconds(x);
+ * after the spiSend, where you increment x untill you are satisfied with your
+ * program speed, another trick may be to lower this thread priority : your call
+ */
+static THD_WORKING_AREA(LEDS_THREAD_WA, 128);
+static THD_FUNCTION(ledsThread, arg) {
+  (void) arg;
+  while(1){
+    spiSend(&WS2812_SPI, PREAMBLE_SIZE + DATA_SIZE + RESET_SIZE, txbuf);
+  }
+}
+
+ static const SPIConfig spicfg = {
+  NULL,
+  PORT_WS2812,
+  PIN_WS2812,
+  SPI_CR1_BR_1|SPI_CR1_BR_0 // baudrate : fpclk / 8 => 1tick is 0.32us (2.25 MHz)
+};
+
+ /*
+ * Function used to initialize the driver.
+ *
+ * Starts by shutting off all the LEDs.
+ * Then gets access on the LED_SPI driver.
+ * May eventually launch an animation on the LEDs (e.g. a thread setting the
+ * txbuff values)
+ */
+void leds_init(void){
+  /* MOSI pin*/
+  palSetPadMode(PORT_WS2812, PIN_WS2812, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
+  for(int i = 0; i < RESET_SIZE; i++)
+    txbuf[DATA_SIZE+i] = 0x00;
+  for (int i=0; i<PREAMBLE_SIZE; i++)
+    txbuf[i] = 0x00;
+  spiAcquireBus(&WS2812_SPI);              /* Acquire ownership of the bus.    */
+  spiStart(&WS2812_SPI, &spicfg);          /* Setup transfer parameters.       */
+  spiSelect(&WS2812_SPI);                  /* Slave Select assertion.          */
+  chThdCreateStatic(LEDS_THREAD_WA, sizeof(LEDS_THREAD_WA),NORMALPRIO, ledsThread, NULL);
+}
+
+ /*
+ * 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
+ * 0s and 1s for the LED (with the appropriate timing).
+ */
+static uint8_t get_protocol_eq(uint8_t data, int pos){
+  uint8_t eq = 0;
+  if (data & (1 << (2*(3-pos))))
+    eq = 0b1110;
+  else
+    eq = 0b1000;
+  if (data & (2 << (2*(3-pos))))
+    eq += 0b11100000;
+  else
+    eq += 0b10000000;
+  return eq;
+}
+
+
+ void WS2812_init(void) {
+  leds_init();
+}
+
+ 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
+ * 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
+ * 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_rgb(LED_TYPE color, int pos){
+  for(int j = 0; j < 4; j++)
+    txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + j] = get_protocol_eq(color.g, j);
+  for(int j = 0; j < 4; j++)
+    txbuf[PREAMBLE_SIZE + BYTES_FOR_LED*pos + BYTES_FOR_LED_BYTE+j] = get_protocol_eq(color.r, j);
+  for(int j = 0; j < 4; 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){
+  for(int i = 0; i < NB_LEDS; i++)
+    set_led_color_rgb(color, i);
+}
+
+
+ void ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t number_of_leds) {
+
+ }
diff --git a/keyboards/handwired/practice60/ws2812.h b/keyboards/handwired/practice60/ws2812.h
new file mode 100644 (file)
index 0000000..3b61ddc
--- /dev/null
@@ -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);
index cf2666eb4b65c3b0843726ec954ad3508d922e3b..22dce963c97b0a8217a4159feab13e85b9e1a7f8 100644 (file)
   #include <avr/eeprom.h>
   #include <avr/interrupt.h>
 #endif
+#ifdef STM32_EEPROM_ENABLE
+  #include "hal.h"
+  #include "eeprom.h"
+  #include "eeprom_stm32.h"
+#endif
 #include "wait.h"
 #include "progmem.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) {
-  #ifdef __AVR__
+  #if defined(__AVR__) || defined(STM32_EEPROM_ENABLE) || defined(PROTOCOL_ARM_ATSAM) || defined(EEPROM_SIZE)
     return eeprom_read_dword(EECONFIG_RGBLIGHT);
   #else
     return 0;
   #endif
 }
 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) {
     eeprom_update_dword(EECONFIG_RGBLIGHT, val);
   }
@@ -333,7 +338,7 @@ void rgblight_disable_noeeprom(void) {
 #ifdef RGBLIGHT_USE_TIMER
     rgblight_timer_disable();
 #endif
-  _delay_ms(50);
+  wait_ms(50);
   rgblight_set();
 }
 
index a15430d676c59300618cd84fb9bc6b8888fa904e..17d38af6a07307983db2dd4eac8ee156f1387c27 100755 (executable)
@@ -75,17 +75,13 @@ uint16_t EEPROM_WriteDataByte (uint16_t Address, uint8_t DataByte) {
     }
 
     // calculate which page is affected (Pagenum1/Pagenum2...PagenumN)
-    page = (FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address)) & 0x00000FFF;
-
-    if (page % FEE_PAGE_SIZE) page = page + FEE_PAGE_SIZE;
-    page = (page / FEE_PAGE_SIZE) - 1;
+    page = FEE_ADDR_OFFSET(Address) / FEE_PAGE_SIZE;
 
     // 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) {
 
         FlashStatus = FLASH_ProgramHalfWord(FEE_PAGE_BASE_ADDRESS + FEE_ADDR_OFFSET(Address), (uint16_t)(0x00FF & DataByte));
-    }
-    else {
+    } else {
 
         // 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
@@ -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
-        DataBuf[FEE_ADDR_OFFSET(Address)] = DataByte;
+        DataBuf[FEE_ADDR_OFFSET(Address) % FEE_PAGE_SIZE] = DataByte;
 
         //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++) {
             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)]));
             }
         }
-
     }
     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)
 {
     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);
 }