diff options
Diffstat (limited to 'drivers/avr/ws2812.c')
| -rw-r--r-- | drivers/avr/ws2812.c | 384 |
1 files changed, 179 insertions, 205 deletions
diff --git a/drivers/avr/ws2812.c b/drivers/avr/ws2812.c index 7c3cb5174..0a02c6f7f 100644 --- a/drivers/avr/ws2812.c +++ b/drivers/avr/ws2812.c | |||
| @@ -1,25 +1,25 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * light weight WS2812 lib V2.0b | 2 | * light weight WS2812 lib V2.0b |
| 3 | * | 3 | * |
| 4 | * Controls WS2811/WS2812/WS2812B RGB-LEDs | 4 | * Controls WS2811/WS2812/WS2812B RGB-LEDs |
| 5 | * Author: Tim (cpldcpu@gmail.com) | 5 | * Author: Tim (cpldcpu@gmail.com) |
| 6 | * | 6 | * |
| 7 | * Jan 18th, 2014 v2.0b Initial Version | 7 | * Jan 18th, 2014 v2.0b Initial Version |
| 8 | * Nov 29th, 2015 v2.3 Added SK6812RGBW support | 8 | * Nov 29th, 2015 v2.3 Added SK6812RGBW support |
| 9 | * | 9 | * |
| 10 | * This program is free software: you can redistribute it and/or modify | 10 | * This program is free software: you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| 12 | * the Free Software Foundation, either version 2 of the License, or | 12 | * the Free Software Foundation, either version 2 of the License, or |
| 13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
| 14 | * | 14 | * |
| 15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
| 19 | * | 19 | * |
| 20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
| 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include "ws2812.h" | 24 | #include "ws2812.h" |
| 25 | #include <avr/interrupt.h> | 25 | #include <avr/interrupt.h> |
| @@ -30,44 +30,40 @@ | |||
| 30 | #if !defined(LED_ARRAY) && defined(RGB_MATRIX_ENABLE) | 30 | #if !defined(LED_ARRAY) && defined(RGB_MATRIX_ENABLE) |
| 31 | // LED color buffer | 31 | // LED color buffer |
| 32 | LED_TYPE led[DRIVER_LED_TOTAL]; | 32 | LED_TYPE led[DRIVER_LED_TOTAL]; |
| 33 | #define LED_ARRAY led | 33 | # define LED_ARRAY led |
| 34 | #endif | 34 | #endif |
| 35 | 35 | ||
| 36 | #ifdef RGBW_BB_TWI | 36 | #ifdef RGBW_BB_TWI |
| 37 | 37 | ||
| 38 | // Port for the I2C | 38 | // Port for the I2C |
| 39 | #define I2C_DDR DDRD | 39 | # define I2C_DDR DDRD |
| 40 | #define I2C_PIN PIND | 40 | # define I2C_PIN PIND |
| 41 | #define I2C_PORT PORTD | 41 | # define I2C_PORT PORTD |
| 42 | 42 | ||
| 43 | // Pins to be used in the bit banging | 43 | // Pins to be used in the bit banging |
| 44 | #define I2C_CLK 0 | 44 | # define I2C_CLK 0 |
| 45 | #define I2C_DAT 1 | 45 | # define I2C_DAT 1 |
| 46 | 46 | ||
| 47 | #define I2C_DATA_HI()\ | 47 | # define I2C_DATA_HI() \ |
| 48 | I2C_DDR &= ~ (1 << I2C_DAT);\ | 48 | I2C_DDR &= ~(1 << I2C_DAT); \ |
| 49 | I2C_PORT |= (1 << I2C_DAT); | 49 | I2C_PORT |= (1 << I2C_DAT); |
| 50 | #define I2C_DATA_LO()\ | 50 | # define I2C_DATA_LO() \ |
| 51 | I2C_DDR |= (1 << I2C_DAT);\ | 51 | I2C_DDR |= (1 << I2C_DAT); \ |
| 52 | I2C_PORT &= ~ (1 << I2C_DAT); | 52 | I2C_PORT &= ~(1 << I2C_DAT); |
| 53 | 53 | ||
| 54 | #define I2C_CLOCK_HI()\ | 54 | # define I2C_CLOCK_HI() \ |
| 55 | I2C_DDR &= ~ (1 << I2C_CLK);\ | 55 | I2C_DDR &= ~(1 << I2C_CLK); \ |
| 56 | I2C_PORT |= (1 << I2C_CLK); | 56 | I2C_PORT |= (1 << I2C_CLK); |
| 57 | #define I2C_CLOCK_LO()\ | 57 | # define I2C_CLOCK_LO() \ |
| 58 | I2C_DDR |= (1 << I2C_CLK);\ | 58 | I2C_DDR |= (1 << I2C_CLK); \ |
| 59 | I2C_PORT &= ~ (1 << I2C_CLK); | 59 | I2C_PORT &= ~(1 << I2C_CLK); |
| 60 | 60 | ||
| 61 | #define I2C_DELAY 1 | 61 | # define I2C_DELAY 1 |
| 62 | 62 | ||
| 63 | void I2C_WriteBit(unsigned char c) | 63 | void I2C_WriteBit(unsigned char c) { |
| 64 | { | 64 | if (c > 0) { |
| 65 | if (c > 0) | ||
| 66 | { | ||
| 67 | I2C_DATA_HI(); | 65 | I2C_DATA_HI(); |
| 68 | } | 66 | } else { |
| 69 | else | ||
| 70 | { | ||
| 71 | I2C_DATA_LO(); | 67 | I2C_DATA_LO(); |
| 72 | } | 68 | } |
| 73 | 69 | ||
| @@ -77,8 +73,7 @@ void I2C_WriteBit(unsigned char c) | |||
| 77 | I2C_CLOCK_LO(); | 73 | I2C_CLOCK_LO(); |
| 78 | _delay_us(I2C_DELAY); | 74 | _delay_us(I2C_DELAY); |
| 79 | 75 | ||
| 80 | if (c > 0) | 76 | if (c > 0) { |
| 81 | { | ||
| 82 | I2C_DATA_LO(); | 77 | I2C_DATA_LO(); |
| 83 | } | 78 | } |
| 84 | 79 | ||
| @@ -87,9 +82,8 @@ void I2C_WriteBit(unsigned char c) | |||
| 87 | 82 | ||
| 88 | // Inits bitbanging port, must be called before using the functions below | 83 | // Inits bitbanging port, must be called before using the functions below |
| 89 | // | 84 | // |
| 90 | void I2C_Init(void) | 85 | void I2C_Init(void) { |
| 91 | { | 86 | I2C_PORT &= ~((1 << I2C_DAT) | (1 << I2C_CLK)); |
| 92 | I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); | ||
| 93 | 87 | ||
| 94 | I2C_CLOCK_HI(); | 88 | I2C_CLOCK_HI(); |
| 95 | I2C_DATA_HI(); | 89 | I2C_DATA_HI(); |
| @@ -99,10 +93,9 @@ void I2C_Init(void) | |||
| 99 | 93 | ||
| 100 | // Send a START Condition | 94 | // Send a START Condition |
| 101 | // | 95 | // |
| 102 | void I2C_Start(void) | 96 | void I2C_Start(void) { |
| 103 | { | ||
| 104 | // set both to high at the same time | 97 | // set both to high at the same time |
| 105 | I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); | 98 | I2C_DDR &= ~((1 << I2C_DAT) | (1 << I2C_CLK)); |
| 106 | _delay_us(I2C_DELAY); | 99 | _delay_us(I2C_DELAY); |
| 107 | 100 | ||
| 108 | I2C_DATA_LO(); | 101 | I2C_DATA_LO(); |
| @@ -114,8 +107,7 @@ void I2C_Start(void) | |||
| 114 | 107 | ||
| 115 | // Send a STOP Condition | 108 | // Send a STOP Condition |
| 116 | // | 109 | // |
| 117 | void I2C_Stop(void) | 110 | void I2C_Stop(void) { |
| 118 | { | ||
| 119 | I2C_CLOCK_HI(); | 111 | I2C_CLOCK_HI(); |
| 120 | _delay_us(I2C_DELAY); | 112 | _delay_us(I2C_DELAY); |
| 121 | 113 | ||
| @@ -125,106 +117,91 @@ void I2C_Stop(void) | |||
| 125 | 117 | ||
| 126 | // write a byte to the I2C slave device | 118 | // write a byte to the I2C slave device |
| 127 | // | 119 | // |
| 128 | unsigned char I2C_Write(unsigned char c) | 120 | unsigned char I2C_Write(unsigned char c) { |
| 129 | { | 121 | for (char i = 0; i < 8; i++) { |
| 130 | for (char i = 0; i < 8; i++) | ||
| 131 | { | ||
| 132 | I2C_WriteBit(c & 128); | 122 | I2C_WriteBit(c & 128); |
| 133 | 123 | ||
| 134 | c <<= 1; | 124 | c <<= 1; |
| 135 | } | 125 | } |
| 136 | 126 | ||
| 137 | |||
| 138 | I2C_WriteBit(0); | 127 | I2C_WriteBit(0); |
| 139 | _delay_us(I2C_DELAY); | 128 | _delay_us(I2C_DELAY); |
| 140 | _delay_us(I2C_DELAY); | 129 | _delay_us(I2C_DELAY); |
| 141 | 130 | ||
| 142 | // _delay_us(I2C_DELAY); | 131 | // _delay_us(I2C_DELAY); |
| 143 | //return I2C_ReadBit(); | 132 | // return I2C_ReadBit(); |
| 144 | return 0; | 133 | return 0; |
| 145 | } | 134 | } |
| 146 | 135 | ||
| 147 | |||
| 148 | #endif | 136 | #endif |
| 149 | 137 | ||
| 150 | #ifdef RGB_MATRIX_ENABLE | 138 | #ifdef RGB_MATRIX_ENABLE |
| 151 | // Set an led in the buffer to a color | 139 | // Set an led in the buffer to a color |
| 152 | void inline ws2812_setled(int i, uint8_t r, uint8_t g, uint8_t b) | 140 | void inline ws2812_setled(int i, uint8_t r, uint8_t g, uint8_t b) { |
| 153 | { | ||
| 154 | led[i].r = r; | 141 | led[i].r = r; |
| 155 | led[i].g = g; | 142 | led[i].g = g; |
| 156 | led[i].b = b; | 143 | led[i].b = b; |
| 157 | } | 144 | } |
| 158 | 145 | ||
| 159 | void ws2812_setled_all (uint8_t r, uint8_t g, uint8_t b) | 146 | void ws2812_setled_all(uint8_t r, uint8_t g, uint8_t b) { |
| 160 | { | 147 | for (int i = 0; i < sizeof(led) / sizeof(led[0]); i++) { |
| 161 | for (int i = 0; i < sizeof(led)/sizeof(led[0]); i++) { | 148 | led[i].r = r; |
| 162 | led[i].r = r; | 149 | led[i].g = g; |
| 163 | led[i].g = g; | 150 | led[i].b = b; |
| 164 | led[i].b = b; | 151 | } |
| 165 | } | ||
| 166 | } | 152 | } |
| 167 | #endif | 153 | #endif |
| 168 | 154 | ||
| 169 | // Setleds for standard RGB | 155 | // Setleds for standard RGB |
| 170 | void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) | 156 | void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) { |
| 171 | { | 157 | // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); |
| 172 | // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); | 158 | ws2812_setleds_pin(ledarray, leds, _BV(RGB_DI_PIN & 0xF)); |
| 173 | ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF)); | ||
| 174 | } | 159 | } |
| 175 | 160 | ||
| 176 | void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) | 161 | void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) { |
| 177 | { | 162 | // ws2812_DDRREG |= pinmask; // Enable DDR |
| 178 | // ws2812_DDRREG |= pinmask; // Enable DDR | 163 | // new universal format (DDR) |
| 179 | // new universal format (DDR) | 164 | _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask; |
| 180 | _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= pinmask; | ||
| 181 | 165 | ||
| 182 | ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask); | 166 | ws2812_sendarray_mask((uint8_t *)ledarray, leds + leds + leds, pinmask); |
| 183 | _delay_us(50); | 167 | _delay_us(50); |
| 184 | } | 168 | } |
| 185 | 169 | ||
| 186 | // Setleds for SK6812RGBW | 170 | // Setleds for SK6812RGBW |
| 187 | void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) | 171 | void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) { |
| 188 | { | 172 | #ifdef RGBW_BB_TWI |
| 189 | |||
| 190 | #ifdef RGBW_BB_TWI | ||
| 191 | uint8_t sreg_prev, twcr_prev; | 173 | uint8_t sreg_prev, twcr_prev; |
| 192 | sreg_prev=SREG; | 174 | sreg_prev = SREG; |
| 193 | twcr_prev=TWCR; | 175 | twcr_prev = TWCR; |
| 194 | cli(); | 176 | cli(); |
| 195 | TWCR &= ~(1<<TWEN); | 177 | TWCR &= ~(1 << TWEN); |
| 196 | I2C_Init(); | 178 | I2C_Init(); |
| 197 | I2C_Start(); | 179 | I2C_Start(); |
| 198 | I2C_Write(0x84); | 180 | I2C_Write(0x84); |
| 199 | uint16_t datlen = leds<<2; | 181 | uint16_t datlen = leds << 2; |
| 200 | uint8_t curbyte; | 182 | uint8_t curbyte; |
| 201 | uint8_t * data = (uint8_t*)ledarray; | 183 | uint8_t *data = (uint8_t *)ledarray; |
| 202 | while (datlen--) { | 184 | while (datlen--) { |
| 203 | curbyte=*data++; | 185 | curbyte = *data++; |
| 204 | I2C_Write(curbyte); | 186 | I2C_Write(curbyte); |
| 205 | } | 187 | } |
| 206 | I2C_Stop(); | 188 | I2C_Stop(); |
| 207 | SREG=sreg_prev; | 189 | SREG = sreg_prev; |
| 208 | TWCR=twcr_prev; | 190 | TWCR = twcr_prev; |
| 209 | #endif | 191 | #endif |
| 210 | |||
| 211 | |||
| 212 | // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR | ||
| 213 | // new universal format (DDR) | ||
| 214 | _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF); | ||
| 215 | 192 | ||
| 216 | ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF)); | 193 | // ws2812_DDRREG |= _BV(ws2812_pin); // Enable DDR |
| 194 | // new universal format (DDR) | ||
| 195 | _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF); | ||
| 217 | 196 | ||
| 197 | ws2812_sendarray_mask((uint8_t *)ledarray, leds << 2, _BV(RGB_DI_PIN & 0xF)); | ||
| 218 | 198 | ||
| 219 | #ifndef RGBW_BB_TWI | 199 | #ifndef RGBW_BB_TWI |
| 220 | _delay_us(80); | 200 | _delay_us(80); |
| 221 | #endif | 201 | #endif |
| 222 | } | 202 | } |
| 223 | 203 | ||
| 224 | void ws2812_sendarray(uint8_t *data,uint16_t datlen) | 204 | void ws2812_sendarray(uint8_t *data, uint16_t datlen) { ws2812_sendarray_mask(data, datlen, _BV(RGB_DI_PIN & 0xF)); } |
| 225 | { | ||
| 226 | ws2812_sendarray_mask(data,datlen,_BV(RGB_DI_PIN & 0xF)); | ||
| 227 | } | ||
| 228 | 205 | ||
| 229 | /* | 206 | /* |
| 230 | This routine writes an array of bytes with RGB values to the Dataout pin | 207 | This routine writes an array of bytes with RGB values to the Dataout pin |
| @@ -232,136 +209,133 @@ void ws2812_sendarray(uint8_t *data,uint16_t datlen) | |||
| 232 | */ | 209 | */ |
| 233 | 210 | ||
| 234 | // Timing in ns | 211 | // Timing in ns |
| 235 | #define w_zeropulse 350 | 212 | #define w_zeropulse 350 |
| 236 | #define w_onepulse 900 | 213 | #define w_onepulse 900 |
| 237 | #define w_totalperiod 1250 | 214 | #define w_totalperiod 1250 |
| 238 | 215 | ||
| 239 | // Fixed cycles used by the inner loop | 216 | // Fixed cycles used by the inner loop |
| 240 | #define w_fixedlow 2 | 217 | #define w_fixedlow 2 |
| 241 | #define w_fixedhigh 4 | 218 | #define w_fixedhigh 4 |
| 242 | #define w_fixedtotal 8 | 219 | #define w_fixedtotal 8 |
| 243 | 220 | ||
| 244 | // Insert NOPs to match the timing, if possible | 221 | // Insert NOPs to match the timing, if possible |
| 245 | #define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000) | 222 | #define w_zerocycles (((F_CPU / 1000) * w_zeropulse) / 1000000) |
| 246 | #define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000) | 223 | #define w_onecycles (((F_CPU / 1000) * w_onepulse + 500000) / 1000000) |
| 247 | #define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000) | 224 | #define w_totalcycles (((F_CPU / 1000) * w_totalperiod + 500000) / 1000000) |
| 248 | 225 | ||
| 249 | // w1 - nops between rising edge and falling edge - low | 226 | // w1 - nops between rising edge and falling edge - low |
| 250 | #define w1 (w_zerocycles-w_fixedlow) | 227 | #define w1 (w_zerocycles - w_fixedlow) |
| 251 | // w2 nops between fe low and fe high | 228 | // w2 nops between fe low and fe high |
| 252 | #define w2 (w_onecycles-w_fixedhigh-w1) | 229 | #define w2 (w_onecycles - w_fixedhigh - w1) |
| 253 | // w3 nops to complete loop | 230 | // w3 nops to complete loop |
| 254 | #define w3 (w_totalcycles-w_fixedtotal-w1-w2) | 231 | #define w3 (w_totalcycles - w_fixedtotal - w1 - w2) |
| 255 | 232 | ||
| 256 | #if w1>0 | 233 | #if w1 > 0 |
| 257 | #define w1_nops w1 | 234 | # define w1_nops w1 |
| 258 | #else | 235 | #else |
| 259 | #define w1_nops 0 | 236 | # define w1_nops 0 |
| 260 | #endif | 237 | #endif |
| 261 | 238 | ||
| 262 | // The only critical timing parameter is the minimum pulse length of the "0" | 239 | // The only critical timing parameter is the minimum pulse length of the "0" |
| 263 | // Warn or throw error if this timing can not be met with current F_CPU settings. | 240 | // Warn or throw error if this timing can not be met with current F_CPU settings. |
| 264 | #define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000) | 241 | #define w_lowtime ((w1_nops + w_fixedlow) * 1000000) / (F_CPU / 1000) |
| 265 | #if w_lowtime>550 | 242 | #if w_lowtime > 550 |
| 266 | #error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" | 243 | # error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?" |
| 267 | #elif w_lowtime>450 | 244 | #elif w_lowtime > 450 |
| 268 | #warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." | 245 | # warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)." |
| 269 | #warning "Please consider a higher clockspeed, if possible" | 246 | # warning "Please consider a higher clockspeed, if possible" |
| 270 | #endif | 247 | #endif |
| 271 | 248 | ||
| 272 | #if w2>0 | 249 | #if w2 > 0 |
| 273 | #define w2_nops w2 | 250 | # define w2_nops w2 |
| 274 | #else | 251 | #else |
| 275 | #define w2_nops 0 | 252 | # define w2_nops 0 |
| 276 | #endif | 253 | #endif |
| 277 | 254 | ||
| 278 | #if w3>0 | 255 | #if w3 > 0 |
| 279 | #define w3_nops w3 | 256 | # define w3_nops w3 |
| 280 | #else | 257 | #else |
| 281 | #define w3_nops 0 | 258 | # define w3_nops 0 |
| 282 | #endif | 259 | #endif |
| 283 | 260 | ||
| 284 | #define w_nop1 "nop \n\t" | 261 | #define w_nop1 "nop \n\t" |
| 285 | #define w_nop2 "rjmp .+0 \n\t" | 262 | #define w_nop2 "rjmp .+0 \n\t" |
| 286 | #define w_nop4 w_nop2 w_nop2 | 263 | #define w_nop4 w_nop2 w_nop2 |
| 287 | #define w_nop8 w_nop4 w_nop4 | 264 | #define w_nop8 w_nop4 w_nop4 |
| 288 | #define w_nop16 w_nop8 w_nop8 | 265 | #define w_nop16 w_nop8 w_nop8 |
| 289 | 266 | ||
| 290 | void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) | 267 | void inline ws2812_sendarray_mask(uint8_t *data, uint16_t datlen, uint8_t maskhi) { |
| 291 | { | 268 | uint8_t curbyte, ctr, masklo; |
| 292 | uint8_t curbyte,ctr,masklo; | 269 | uint8_t sreg_prev; |
| 293 | uint8_t sreg_prev; | 270 | |
| 294 | 271 | // masklo =~maskhi&ws2812_PORTREG; | |
| 295 | // masklo =~maskhi&ws2812_PORTREG; | 272 | // maskhi |= ws2812_PORTREG; |
| 296 | // maskhi |= ws2812_PORTREG; | 273 | masklo = ~maskhi & _SFR_IO8((RGB_DI_PIN >> 4) + 2); |
| 297 | masklo =~maskhi&_SFR_IO8((RGB_DI_PIN >> 4) + 2); | 274 | maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2); |
| 298 | maskhi |= _SFR_IO8((RGB_DI_PIN >> 4) + 2); | 275 | sreg_prev = SREG; |
| 299 | sreg_prev=SREG; | 276 | cli(); |
| 300 | cli(); | 277 | |
| 301 | 278 | while (datlen--) { | |
| 302 | while (datlen--) { | 279 | curbyte = (*data++); |
| 303 | curbyte=(*data++); | 280 | |
| 304 | 281 | asm volatile(" ldi %0,8 \n\t" | |
| 305 | asm volatile( | 282 | "loop%=: \n\t" |
| 306 | " ldi %0,8 \n\t" | 283 | " out %2,%3 \n\t" // '1' [01] '0' [01] - re |
| 307 | "loop%=: \n\t" | 284 | #if (w1_nops & 1) |
| 308 | " out %2,%3 \n\t" // '1' [01] '0' [01] - re | 285 | w_nop1 |
| 309 | #if (w1_nops&1) | ||
| 310 | w_nop1 | ||
| 311 | #endif | 286 | #endif |
| 312 | #if (w1_nops&2) | 287 | #if (w1_nops & 2) |
| 313 | w_nop2 | 288 | w_nop2 |
| 314 | #endif | 289 | #endif |
| 315 | #if (w1_nops&4) | 290 | #if (w1_nops & 4) |
| 316 | w_nop4 | 291 | w_nop4 |
| 317 | #endif | 292 | #endif |
| 318 | #if (w1_nops&8) | 293 | #if (w1_nops & 8) |
| 319 | w_nop8 | 294 | w_nop8 |
| 320 | #endif | 295 | #endif |
| 321 | #if (w1_nops&16) | 296 | #if (w1_nops & 16) |
| 322 | w_nop16 | 297 | w_nop16 |
| 323 | #endif | 298 | #endif |
| 324 | " sbrs %1,7 \n\t" // '1' [03] '0' [02] | 299 | " sbrs %1,7 \n\t" // '1' [03] '0' [02] |
| 325 | " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low | 300 | " out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low |
| 326 | " lsl %1 \n\t" // '1' [04] '0' [04] | 301 | " lsl %1 \n\t" // '1' [04] '0' [04] |
| 327 | #if (w2_nops&1) | 302 | #if (w2_nops & 1) |
| 328 | w_nop1 | 303 | w_nop1 |
| 329 | #endif | 304 | #endif |
| 330 | #if (w2_nops&2) | 305 | #if (w2_nops & 2) |
| 331 | w_nop2 | 306 | w_nop2 |
| 332 | #endif | 307 | #endif |
| 333 | #if (w2_nops&4) | 308 | #if (w2_nops & 4) |
| 334 | w_nop4 | 309 | w_nop4 |
| 335 | #endif | 310 | #endif |
| 336 | #if (w2_nops&8) | 311 | #if (w2_nops & 8) |
| 337 | w_nop8 | 312 | w_nop8 |
| 338 | #endif | 313 | #endif |
| 339 | #if (w2_nops&16) | 314 | #if (w2_nops & 16) |
| 340 | w_nop16 | 315 | w_nop16 |
| 341 | #endif | 316 | #endif |
| 342 | " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high | 317 | " out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high |
| 343 | #if (w3_nops&1) | 318 | #if (w3_nops & 1) |
| 344 | w_nop1 | 319 | w_nop1 |
| 345 | #endif | 320 | #endif |
| 346 | #if (w3_nops&2) | 321 | #if (w3_nops & 2) |
| 347 | w_nop2 | 322 | w_nop2 |
| 348 | #endif | 323 | #endif |
| 349 | #if (w3_nops&4) | 324 | #if (w3_nops & 4) |
| 350 | w_nop4 | 325 | w_nop4 |
| 351 | #endif | 326 | #endif |
| 352 | #if (w3_nops&8) | 327 | #if (w3_nops & 8) |
| 353 | w_nop8 | 328 | w_nop8 |
| 354 | #endif | 329 | #endif |
| 355 | #if (w3_nops&16) | 330 | #if (w3_nops & 16) |
| 356 | w_nop16 | 331 | w_nop16 |
| 357 | #endif | 332 | #endif |
| 358 | 333 | ||
| 359 | " dec %0 \n\t" // '1' [+2] '0' [+2] | 334 | " dec %0 \n\t" // '1' [+2] '0' [+2] |
| 360 | " brne loop%=\n\t" // '1' [+3] '0' [+4] | 335 | " brne loop%=\n\t" // '1' [+3] '0' [+4] |
| 361 | : "=&d" (ctr) | 336 | : "=&d"(ctr) |
| 362 | : "r" (curbyte), "I" (_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r" (maskhi), "r" (masklo) | 337 | : "r"(curbyte), "I"(_SFR_IO_ADDR(_SFR_IO8((RGB_DI_PIN >> 4) + 2))), "r"(maskhi), "r"(masklo)); |
| 363 | ); | 338 | } |
| 364 | } | ||
| 365 | 339 | ||
| 366 | SREG=sreg_prev; | 340 | SREG = sreg_prev; |
| 367 | } | 341 | } |
