Browse Source

Add software UART and battery monitor

tmk 11 năm trước cách đây
mục cha
commit
862f519e24

+ 1 - 0
keyboard/hhkb_rn42/Makefile

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

+ 7 - 0
keyboard/hhkb_rn42/config.h

@@ -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.

+ 46 - 3
keyboard/hhkb_rn42/main.c

@@ -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;

+ 4 - 0
keyboard/hhkb_rn42/rn42.c

@@ -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

+ 5 - 0
keyboard/hhkb_rn42/rn42.h

@@ -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 - 0
keyboard/hhkb_rn42/suart.S

@@ -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

+ 8 - 0
keyboard/hhkb_rn42/suart.h

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