Add software UART and battery monitor

This commit is contained in:
tmk 2014-07-14 15:20:10 +09:00
parent 01fa462e2c
commit 862f519e24
7 changed files with 227 additions and 3 deletions

View file

@ -53,6 +53,7 @@ SRC += keymap_common.c \
matrix.c \
led.c \
serial_uart.c \
suart.S \
rn42.c \
main.c

View file

@ -76,6 +76,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
/* for debug */
#define SUART_OUT_PORT PORTD
#define SUART_OUT_BIT 0
#define SUART_IN_PIN PIND
#define SUART_IN_BIT 1
/*
* Feature disable options
* These options are also useful to firmware size reduction.

View file

@ -12,10 +12,16 @@
#include "action.h"
#include "action_util.h"
#include "wait.h"
#include "suart.h"
bool config_mode = false;
static int8_t sendchar_func(uint8_t c)
{
sendchar(c); // LUFA
xmit(c); // SUART
}
static void SetupHardware(void)
{
/* Disable watchdog if enabled by bootloader/fuses */
@ -32,7 +38,16 @@ static void SetupHardware(void)
// for Console_Task
USB_Device_EnableSOFEvents();
print_set_sendchar(sendchar);
print_set_sendchar(sendchar_func);
// SUART PD0:output, PD1:input
DDRD |= (1<<0);
PORTD |= (1<<0);
DDRD &= ~(1<<1);
PORTD |= (1<<1);
// CTS control
CTS_INIT();
}
static bool force_usb = false;
@ -70,6 +85,12 @@ int main(void)
sleep_led_init();
#endif
// ADC for battery
//ADMUX = (1<<REFS0); // Ref:AVCC, Input:ADC0(PF0)
ADMUX = (1<<REFS1) | (1<<REFS0); // Ref:AVCC, Input:ADC0(PF0)
ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Prescale:128
ADCSRA |= (1<<ADEN); // enable ADC
print("Keyboard start.\n");
while (1) {
/*
@ -89,7 +110,12 @@ int main(void)
int16_t c;
if (config_mode) {
while ((c = serial_recv2()) != -1) xprintf("%c", c);
while ((c = serial_recv2()) != -1) {
// without flow control it'll fail to receive data when flooded
CTS_HI();
xprintf("%c", c);
CTS_LO();
}
} else {
while ((c = serial_recv2()) != -1) {
// LED Out report: 0xFE, 0x02, 0x01, <leds>
@ -146,6 +172,7 @@ bool command_extra(uint8_t code)
print("a: Bluetooth auto connect\n");
print("del: Bluetooth disconnect\n");
print("i: info\n");
print("b: battery voltage\n");
if (config_mode) {
return true;
@ -208,6 +235,22 @@ bool command_extra(uint8_t code)
xprintf("rn42_ready(): %X\n", rn42_ready());
xprintf("config_mode: %X\n", config_mode);
return true;
case KC_B:
// battery monitor
ADCSRA |= (1<<ADEN) | (1<<ADSC);
while (ADCSRA & (1<<ADSC)) ;
uint16_t bat = ADCL;
bat = ADCH<<8 | bat;
xprintf("BAT: %04X\n", bat);
ADCSRA |= (1<<ADEN) | (1<<ADSC);
while (ADCSRA & (1<<ADSC)) ;
bat = ADCL;
bat = ADCH<<8 | bat;
xprintf("BAT: %04X\n", bat);
ADCSRA &= ~(1<<ADEN);
return true;
default:
if (config_mode)
return true;

View file

@ -70,9 +70,11 @@ static uint8_t keyboard_leds(void) { return 0; }
static void send_keyboard(report_keyboard_t *report)
{
// wake from deep sleep
/*
PORTD |= (1<<5); // high
wait_ms(5);
PORTD &= ~(1<<5); // low
*/
serial_send(0xFD); // Raw report mode
serial_send(9); // length
@ -90,9 +92,11 @@ static void send_keyboard(report_keyboard_t *report)
static void send_mouse(report_mouse_t *report)
{
// wake from deep sleep
/*
PORTD |= (1<<5); // high
wait_ms(5);
PORTD &= ~(1<<5); // low
*/
serial_send(0xFD); // Raw report mode
serial_send(5); // length

View file

@ -3,6 +3,11 @@
#include <stdbool.h>
// RN-42 CTS pin
#define CTS_INIT() (DDRD |= (1<<5))
#define CTS_HI() (PORTD |= (1<<5))
#define CTS_LO() (PORTD &= ~(1<<5))
host_driver_t rn42_driver;
host_driver_t rn42_config_driver;

156
keyboard/hhkb_rn42/suart.S Normal file
View file

@ -0,0 +1,156 @@
;---------------------------------------------------------------------------;
; Software implemented UART module ;
; (C)ChaN, 2005 (http://elm-chan.org/) ;
;---------------------------------------------------------------------------;
; Bit rate settings:
;
; 1MHz 2MHz 4MHz 6MHz 8MHz 10MHz 12MHz 16MHz 20MHz
; 2.4kbps 138 - - - - - - - -
; 4.8kbps 68 138 - - - - - - -
; 9.6kbps 33 68 138 208 - - - - -
; 19.2kbps - 33 68 102 138 173 208 - -
; 38.4kbps - - 33 50 68 85 102 138 172
; 57.6kbps - - 21 33 44 56 68 91 114
; 115.2kbps - - - - 21 27 33 44 56
.nolist
#include <avr/io.h>
.list
#define BPS 44 /* Bit delay. (see above table) */
#define BIDIR 0 /* 0:Separated Tx/Rx, 1:Shared Tx/Rx */
#define OUT_1 sbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 1 */
#define OUT_0 cbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 0 */
#define SKIP_IN_1 sbis _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 1 */
#define SKIP_IN_0 sbic _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 0 */
#ifdef SPM_PAGESIZE
.macro _LPMI reg
lpm \reg, Z+
.endm
.macro _MOVW dh,dl, sh,sl
movw \dl, \sl
.endm
#else
.macro _LPMI reg
lpm
mov \reg, r0
adiw ZL, 1
.endm
.macro _MOVW dh,dl, sh,sl
mov \dl, \sl
mov \dh, \sh
.endm
#endif
;---------------------------------------------------------------------------;
; Transmit a byte in serial format of N81
;
;Prototype: void xmit (uint8_t data);
;Size: 16 words
.global xmit
.func xmit
xmit:
#if BIDIR
ldi r23, BPS-1 ;Pre-idle time for bidirectional data line
5: dec r23 ;
brne 5b ;/
#endif
in r0, _SFR_IO_ADDR(SREG) ;Save flags
com r24 ;C = start bit
ldi r25, 10 ;Bit counter
cli ;Start critical section
1: ldi r23, BPS-1 ;----- Bit transferring loop
2: dec r23 ;Wait for a bit time
brne 2b ;/
brcs 3f ;MISO = bit to be sent
OUT_1 ;
3: brcc 4f ;
OUT_0 ;/
4: lsr r24 ;Get next bit into C
dec r25 ;All bits sent?
brne 1b ; no, coutinue
out _SFR_IO_ADDR(SREG), r0 ;End of critical section
ret
.endfunc
;---------------------------------------------------------------------------;
; Receive a byte
;
;Prototype: uint8_t rcvr (void);
;Size: 19 words
.global rcvr
.func rcvr
rcvr:
in r0, _SFR_IO_ADDR(SREG) ;Save flags
ldi r24, 0x80 ;Receiving shift reg
cli ;Start critical section
1: SKIP_IN_1 ;Wait for idle
rjmp 1b
2: SKIP_IN_0 ;Wait for start bit
rjmp 2b
ldi r25, BPS/2 ;Wait for half bit time
3: dec r25
brne 3b
4: ldi r25, BPS ;----- Bit receiving loop
5: dec r25 ;Wait for a bit time
brne 5b ;/
lsr r24 ;Next bit
SKIP_IN_0 ;Get a data bit into r24.7
ori r24, 0x80
brcc 4b ;All bits received? no, continue
out _SFR_IO_ADDR(SREG), r0 ;End of critical section
ret
.endfunc
; Not wait for start bit. This should be called after detecting start bit.
.global recv
.func recv
recv:
in r0, _SFR_IO_ADDR(SREG) ;Save flags
ldi r24, 0x80 ;Receiving shift reg
cli ;Start critical section
;1: SKIP_IN_1 ;Wait for idle
; rjmp 1b
;2: SKIP_IN_0 ;Wait for start bit
; rjmp 2b
ldi r25, BPS/2 ;Wait for half bit time
3: dec r25
brne 3b
4: ldi r25, BPS ;----- Bit receiving loop
5: dec r25 ;Wait for a bit time
brne 5b ;/
lsr r24 ;Next bit
SKIP_IN_0 ;Get a data bit into r24.7
ori r24, 0x80
brcc 4b ;All bits received? no, continue
ldi r25, BPS/2 ;Wait for half bit time
6: dec r25
brne 6b
7: SKIP_IN_1 ;Wait for stop bit
rjmp 7b
out _SFR_IO_ADDR(SREG), r0 ;End of critical section
ret
.endfunc

View file

@ -0,0 +1,8 @@
#ifndef SUART
#define SUART
void xmit(uint8_t);
uint8_t rcvr(void);
uint8_t recv(void);
#endif /* SUART */