From f29443cd40f9050beedab3a822b6e0f24fb789cd Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Tue, 4 May 2021 02:22:31 +0200 Subject: optimized the LED and buzzer wiring * since we use timer 3 exclusively for the buzzer but trigger the pin using an IRQ handler, there is no longer any need to occupy a high-resolution pin for the buzzer. * PD5 became a new high resolution LED * PD0 became the new buzzer pin * rearranged the pins used for the different LEDs so that the distribution of high-resolution LEDs is symmetric * Timer 0 is no longer used/modified by setting LEDs. This avoids some workarounds as timer 0 is also used by tmk's timer module. * The song routines could be slightly improved using the timer module. * documented the LED and buzzer pinout in README --- README.md | 14 ++++++++++++-- command.c | 2 +- led.c | 23 +++++++++-------------- matrix.c | 4 ++-- pwm.c | 59 ++++++++--------------------------------------------------- pwm.h | 3 +-- song.c | 51 +++++++++++++++++++-------------------------------- 7 files changed, 52 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index 36f36ca..0516060 100644 --- a/README.md +++ b/README.md @@ -113,11 +113,21 @@ Now, solder wires *on the backside* of the PCBs to the following pins of the for ![8212](docs/8212.jpg) -These wires connect to the Teensy in the following order: __FIXME__ +These wires connect to the Teensy in the following order: + +8212 Pin | Teensy Pin +-------- | ---------- +4 | PB5 +6 | PD1 +8 | PB7 +10 | PB4 +15 | PB6 +17 | PD2 +21 | PD3 Desolder the buzzer's 390R resistor and connect the side *facing away* from it to a jumper cable. -It will connect to pin __FIXME__ of the Teensy. +It will connect to pin PD0 of the Teensy. Desolder the IFFS cable. diff --git a/command.c b/command.c index 6827706..cb0c270 100644 --- a/command.c +++ b/command.c @@ -38,7 +38,7 @@ bool command_extra(uint8_t code) dprintf("new keyclick mode: %u\n", keyclick_mode); /* FIXME: Perhaps do this in matrix_scan() */ keyclick_solenoid_set(false); - pwm_pb5_set_tone(0); + pwm_pd0_set_tone(0); /* update the keyclick mode LED */ led_set(host_keyboard_leds()); return true; diff --git a/led.c b/led.c index c7e5933..0d92563 100644 --- a/led.c +++ b/led.c @@ -40,33 +40,28 @@ void led_set(uint8_t usb_led) else PORTD |= (1 << PD3); - /* - * 1st LED on first row (G00). - * - * NOTE: This will automatically disable PWM mode, so it will not - * interfere with timer 0 and tmk's timer module. - */ - pwm_pd0_set_led(usb_led & (1 << USB_LED_NUM_LOCK) ? 255 : 0); + /* 1st LED on first row (G00). */ + pwm_pb5_set_led(usb_led & (1 << USB_LED_NUM_LOCK) ? 255 : 0); /* 2nd LED on first row (G01): Highlight keyclick mode. */ - pwm_pb7_set_led(keyclick_mode*255/(KEYCLICK_MAX-1)); + pwm_pd1_set_led(keyclick_mode*255/(KEYCLICK_MAX-1)); /* 3rd LED on the first row (G02) */ - pwm_pd1_set_led(usb_led & (1 << USB_LED_COMPOSE) ? 255 : 0); + pwm_pb7_set_led(usb_led & (1 << USB_LED_COMPOSE) ? 255 : 0); /* * 4th LED (G03) are currently not triggerable via USB. * Could be triggered as the "backlight". */ - pwm_pb6_set_led(0); + pwm_pb4_set_led(0); /* 5th LED on the first row (G04) */ - pwm_pb4_set_led(usb_led & (1 << USB_LED_SCROLL_LOCK) ? 255 : 0); + pwm_pb6_set_led(usb_led & (1 << USB_LED_SCROLL_LOCK) ? 255 : 0); /* * 6th LED on the first row (G53). * - * Triggering this LED (PD2) will also enable the buzzer (PB5), + * Triggering this LED (PD2) will also enable the buzzer (PD0), * so we have got a way to beep from userspace (see ./k7637-beep.sh). * * The original firmware also had the error display on G53 @@ -74,9 +69,9 @@ void led_set(uint8_t usb_led) */ if (usb_led & (1 << USB_LED_KANA)) { PORTD &= ~(1 << PD2); - pwm_pb5_set_tone(2200); + pwm_pd0_set_tone(2200); } else { PORTD |= (1 << PD2); - pwm_pb5_set_tone(0); + pwm_pd0_set_tone(0); } } diff --git a/matrix.c b/matrix.c index 5c4ecbd..cbb011d 100644 --- a/matrix.c +++ b/matrix.c @@ -143,7 +143,7 @@ uint8_t matrix_scan(void) case KEYCLICK_BUZZER: if (matrix_debouncing_pressed_keys > matrix_pressed_keys) { - pwm_pb5_set_tone(550); + pwm_pd0_set_tone(550); keyclick_time = timer_read(); } break; @@ -229,7 +229,7 @@ uint8_t matrix_scan(void) case KEYCLICK_BUZZER: if (!(host_keyboard_leds() & (1 << USB_LED_KANA))) - pwm_pb5_set_tone(0); + pwm_pd0_set_tone(0); break; default: diff --git a/pwm.c b/pwm.c index 97c3dac..82fd106 100644 --- a/pwm.c +++ b/pwm.c @@ -96,47 +96,6 @@ static const uint16_t pwm_table16[256] PROGMEM = { 0xF888, 0xFB02, 0xFD7E, 0xFFFF }; -/** - * Configure a PWM pin of Timer 0 (8-bit resolution). - * - * @note Timer 0 is used by tmk's timer module as well. - * You can therefore only temporarilly PWM-modulate using timer 0 - * (ie. NOT during matrix scanning), cannot use any timer module functions - * and should call timer_init() afterwards. - * This can be easily resolved by using pwm_pb5_set_led() for one of the LEDs - * and redistribute all the LED. - * The buzzer can then use the no longer used PD0 since it's manually - * IRQ-triggered anyway. - * - * @param channel Channel to initialize. - * 0 (OC0A/PB7), 1 (OC0B/PD0) - */ -static void pwm_timer0_init(uint8_t channel) -{ - /* Fast PWM on OC0x, inverted duty cycle, TOP = 0xFF */ - TCCR0A |= (0b11 << (3-channel)*2) | 0b11; - /* no prescaling */ - TCCR0B = 0b00000001; -} - -void pwm_pd0_set_led(uint8_t brightness) -{ - switch (brightness) { - case 0: - TCCR0A &= ~0b00110000; - PORTD |= (1 << PD0); - break; - case 255: - TCCR0A &= ~0b00110000; - PORTD &= ~(1 << PD0); - break; - default: - pwm_timer0_init(1); - OCR0B = pgm_read_byte(&pwm_table8[brightness]); - break; - } -} - /** * Configure a PWM pin of Timer 1 (16-bit resolution). * @@ -262,24 +221,22 @@ void pwm_pd1_set_led(uint8_t brightness) /** * Set a LED by position in the first row. * - * @bug The pins used should be rescrambled after we freed PD0. - * * @param led LED to set (0-4). * @param brightness Brightness level to set. */ void pwm_set_led(uint8_t led, uint8_t brightness) { switch (led) { - case 0: pwm_pd0_set_led(brightness); break; - case 1: pwm_pb7_set_led(brightness); break; - case 2: pwm_pd1_set_led(brightness); break; - case 3: pwm_pb6_set_led(brightness); break; - case 4: pwm_pb4_set_led(brightness); break; + case 0: pwm_pb5_set_led(brightness); break; + case 1: pwm_pd1_set_led(brightness); break; + case 2: pwm_pb7_set_led(brightness); break; + case 3: pwm_pb4_set_led(brightness); break; + case 4: pwm_pb6_set_led(brightness); break; } } /** - * Play a tone on PB5 (the buzzer). + * Play a tone on PD0 (the buzzer). * * @note This uses timer 3 with an IRQ, even though we cannot * use one of the Timer 3 PWM pins -- they are required for matrix @@ -305,7 +262,7 @@ void pwm_set_led(uint8_t led, uint8_t brightness) * * @param freq Frequency to play. If 0, disables the buzzer. */ -void pwm_pb5_set_tone(uint16_t freq) +void pwm_pd0_set_tone(uint16_t freq) { if (!freq) { /* @@ -343,5 +300,5 @@ void pwm_pb5_set_tone(uint16_t freq) ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) { - PORTB ^= (1 << PB5); + PORTD ^= (1 << PD0); } diff --git a/pwm.h b/pwm.h index f1e0d3f..4a68f4b 100644 --- a/pwm.h +++ b/pwm.h @@ -20,7 +20,6 @@ along with this program. If not, see . #include -void pwm_pd0_set_led(uint8_t brightness); void pwm_pd1_set_led(uint8_t brightness); void pwm_pb4_set_led(uint8_t brightness); void pwm_pb5_set_led(uint8_t brightness); @@ -29,6 +28,6 @@ void pwm_pb7_set_led(uint8_t brightness); void pwm_set_led(uint8_t led, uint8_t brightness); -void pwm_pb5_set_tone(uint16_t freq); +void pwm_pd0_set_tone(uint16_t freq); #endif diff --git a/song.c b/song.c index 4abbb03..d58ff16 100644 --- a/song.c +++ b/song.c @@ -193,11 +193,13 @@ void song_play_ruinen(void) { /* could be activated due to keyclick mode */ keyclick_solenoid_set(false); - pwm_pb5_set_tone(0); + pwm_pd0_set_tone(0); uint8_t i = 0; for (long unsigned int cur_note = 0; cur_note < sizeof(song_ruinen)/sizeof(song_ruinen[0]); cur_note++) { - pwm_pb5_set_tone(pgm_read_word(&song_ruinen[cur_note].freq)); + uint16_t cur_note_time = timer_read(); + + pwm_pd0_set_tone(pgm_read_word(&song_ruinen[cur_note].freq)); uint8_t max_brightness = ((uint32_t)pgm_read_word(&song_ruinen[cur_note].freq)*255)/600; uint16_t fade_dur = pgm_read_word(&song_ruinen[cur_note].dur)/2/(max_brightness+1); @@ -206,14 +208,6 @@ void song_play_ruinen(void) delay_long(fade_dur); } - /* - * The fade duration is probably not very precise, so compensate for it. - * - * FIXME: Once timer 0 is freed, we should use timer_read() and timer_elapsed() - * which will be more precise. - */ - delay_long(pgm_read_word(&song_ruinen[cur_note].dur) - fade_dur*(max_brightness+1)*2); - for (int16_t brightness = max_brightness; brightness >= 0; brightness--) { pwm_set_led(i % 5, brightness); delay_long(fade_dur); @@ -221,12 +215,14 @@ void song_play_ruinen(void) if (pgm_read_word(&song_ruinen[cur_note].freq)) i++; - } - pwm_pb5_set_tone(0); + /* The fade duration is probably not very precise, so compensate for it. */ + uint16_t elapsed = timer_elapsed(cur_note_time); + if (elapsed < pgm_read_word(&song_ruinen[cur_note].dur)) + delay_long(pgm_read_word(&song_ruinen[cur_note].dur) - elapsed); + } - /* we screwed up timer 0 settings and they are also used by the timer module */ - timer_init(); + pwm_pd0_set_tone(0); /* restore the previous lock lights */ led_set(host_keyboard_leds()); @@ -414,7 +410,7 @@ void song_play_kitt(void) { /* could be activated due to keyclick mode */ keyclick_solenoid_set(false); - pwm_pb5_set_tone(0); + pwm_pd0_set_tone(0); int16_t i; @@ -423,38 +419,29 @@ void song_play_kitt(void) song_larsen_light(i); long unsigned int cur_note = 0; - uint16_t cur_note_dur = 0; + uint16_t cur_note_time = timer_read(); int8_t dir = 1; for (i = 0; cur_note < sizeof(song_knight_rider)/sizeof(song_knight_rider[0]); i += dir) { - /* - * FIXME: Once we freed up timer 0 by rearranging the LED pins, - * it might be more precise to use timer_read()/timer_elapsed() to wait for the next note. - */ - if (cur_note_dur < LARSEN_CURVE_STEP) { - cur_note_dur = pgm_read_word(&song_knight_rider[cur_note].dur); - pwm_pb5_set_tone(pgm_read_word(&song_knight_rider[cur_note].freq)); - } + pwm_pd0_set_tone(pgm_read_word(&song_knight_rider[cur_note].freq)); song_larsen_light(i); - cur_note_dur -= LARSEN_CURVE_STEP; - if (cur_note_dur < LARSEN_CURVE_STEP) - cur_note++; - if (i == sizeof(song_larsen_curve)-1 || (dir < 0 && i == 0)) dir *= -1; + + if (timer_elapsed(cur_note_time) >= pgm_read_word(&song_knight_rider[cur_note].dur)) { + cur_note_time = timer_read(); + cur_note++; + } } - pwm_pb5_set_tone(0); + pwm_pd0_set_tone(0); /* fade out larsen light */ while (i < sizeof(song_larsen_curve)*3/2) song_larsen_light(i++); - /* we screwed up timer 0 settings and they are also used by the timer module */ - timer_init(); - /* restore the previous lock lights */ led_set(host_keyboard_leds()); } -- cgit v1.2.3