aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/common/avr
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/common/avr')
-rw-r--r--tmk_core/common/avr/bootloader.c148
-rw-r--r--tmk_core/common/avr/eeconfig.c45
-rw-r--r--tmk_core/common/avr/suspend.c122
-rw-r--r--tmk_core/common/avr/suspend_avr.h27
-rw-r--r--tmk_core/common/avr/timer.c117
-rw-r--r--tmk_core/common/avr/timer_avr.h42
-rw-r--r--tmk_core/common/avr/xprintf.S500
-rw-r--r--tmk_core/common/avr/xprintf.h111
8 files changed, 1112 insertions, 0 deletions
diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c
new file mode 100644
index 000000000..cda295b18
--- /dev/null
+++ b/tmk_core/common/avr/bootloader.c
@@ -0,0 +1,148 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include <avr/io.h>
4#include <avr/interrupt.h>
5#include <avr/wdt.h>
6#include <util/delay.h>
7#include "bootloader.h"
8
9#ifdef PROTOCOL_LUFA
10#include <LUFA/Drivers/USB/USB.h>
11#endif
12
13
14/* Boot Section Size in *BYTEs*
15 * Teensy halfKay 512
16 * Teensy++ halfKay 1024
17 * Atmel DFU loader 4096
18 * LUFA bootloader 4096
19 * USBaspLoader 2048
20 */
21#ifndef BOOTLOADER_SIZE
22#warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h.
23#define BOOTLOADER_SIZE 4096
24#endif
25
26#define FLASH_SIZE (FLASHEND + 1L)
27#define BOOTLOADER_START (FLASH_SIZE - BOOTLOADER_SIZE)
28
29
30/*
31 * Entering the Bootloader via Software
32 * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
33 */
34#define BOOTLOADER_RESET_KEY 0xB007B007
35uint32_t reset_key __attribute__ ((section (".noinit")));
36
37/* initialize MCU status by watchdog reset */
38void bootloader_jump(void) {
39#ifdef PROTOCOL_LUFA
40 USB_Disable();
41 cli();
42 _delay_ms(2000);
43#endif
44
45#ifdef PROTOCOL_PJRC
46 cli();
47 UDCON = 1;
48 USBCON = (1<<FRZCLK);
49 UCSR1B = 0;
50 _delay_ms(5);
51#endif
52
53 // watchdog reset
54 reset_key = BOOTLOADER_RESET_KEY;
55 wdt_enable(WDTO_250MS);
56 for (;;);
57}
58
59
60/* this runs before main() */
61void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3")));
62void bootloader_jump_after_watchdog_reset(void)
63{
64 if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
65 reset_key = 0;
66
67 // My custom USBasploader requires this to come up.
68 MCUSR = 0;
69
70 // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
71 MCUSR &= ~(1<<WDRF);
72 wdt_disable();
73
74 // This is compled into 'icall', address should be in word unit, not byte.
75 ((void (*)(void))(BOOTLOADER_START/2))();
76 }
77}
78
79
80#if 0
81/* Jumping To The Bootloader
82 * http://www.pjrc.com/teensy/jump_to_bootloader.html
83 *
84 * This method doen't work when using LUFA. idk why.
85 * - needs to initialize more regisers or interrupt setting?
86 */
87void bootloader_jump(void) {
88#ifdef PROTOCOL_LUFA
89 USB_Disable();
90 cli();
91 _delay_ms(2000);
92#endif
93
94#ifdef PROTOCOL_PJRC
95 cli();
96 UDCON = 1;
97 USBCON = (1<<FRZCLK);
98 UCSR1B = 0;
99 _delay_ms(5);
100#endif
101
102 /*
103 * Initialize
104 */
105#if defined(__AVR_AT90USB162__)
106 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
107 TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
108 DDRB = 0; DDRC = 0; DDRD = 0;
109 PORTB = 0; PORTC = 0; PORTD = 0;
110#elif defined(__AVR_ATmega32U4__)
111 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
112 TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
113 DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
114 PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
115#elif defined(__AVR_AT90USB646__)
116 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
117 TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
118 DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
119 PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
120#elif defined(__AVR_AT90USB1286__)
121 EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
122 TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
123 DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
124 PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
125#endif
126
127 /*
128 * USBaspLoader
129 */
130#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
131 // This makes custom USBasploader come up.
132 MCUSR = 0;
133
134 // initialize ports
135 PORTB = 0; PORTC= 0; PORTD = 0;
136 DDRB = 0; DDRC= 0; DDRD = 0;
137
138 // disable interrupts
139 EIMSK = 0; EECR = 0; SPCR = 0;
140 ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
141 TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
142 ADCSRA = 0; TWCR = 0; UCSR0B = 0;
143#endif
144
145 // This is compled into 'icall', address should be in word unit, not byte.
146 ((void (*)(void))(BOOTLOADER_START/2))();
147}
148#endif
diff --git a/tmk_core/common/avr/eeconfig.c b/tmk_core/common/avr/eeconfig.c
new file mode 100644
index 000000000..5bd47dc6a
--- /dev/null
+++ b/tmk_core/common/avr/eeconfig.c
@@ -0,0 +1,45 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include <avr/eeprom.h>
4#include "eeconfig.h"
5
6void eeconfig_init(void)
7{
8 eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
9 eeprom_write_byte(EECONFIG_DEBUG, 0);
10 eeprom_write_byte(EECONFIG_DEFAULT_LAYER, 0);
11 eeprom_write_byte(EECONFIG_KEYMAP, 0);
12 eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
13#ifdef BACKLIGHT_ENABLE
14 eeprom_write_byte(EECONFIG_BACKLIGHT, 0);
15#endif
16}
17
18void eeconfig_enable(void)
19{
20 eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
21}
22
23void eeconfig_disable(void)
24{
25 eeprom_write_word(EECONFIG_MAGIC, 0xFFFF);
26}
27
28bool eeconfig_is_enabled(void)
29{
30 return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER);
31}
32
33uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); }
34void eeconfig_write_debug(uint8_t val) { eeprom_write_byte(EECONFIG_DEBUG, val); }
35
36uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
37void eeconfig_write_default_layer(uint8_t val) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER, val); }
38
39uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMAP); }
40void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val); }
41
42#ifdef BACKLIGHT_ENABLE
43uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
44void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); }
45#endif
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c
new file mode 100644
index 000000000..80243f02b
--- /dev/null
+++ b/tmk_core/common/avr/suspend.c
@@ -0,0 +1,122 @@
1#include <stdbool.h>
2#include <avr/sleep.h>
3#include <avr/wdt.h>
4#include <avr/interrupt.h>
5#include "matrix.h"
6#include "action.h"
7#include "backlight.h"
8#include "suspend_avr.h"
9#include "suspend.h"
10#include "timer.h"
11#ifdef PROTOCOL_LUFA
12#include "lufa.h"
13#endif
14
15
16#define wdt_intr_enable(value) \
17__asm__ __volatile__ ( \
18 "in __tmp_reg__,__SREG__" "\n\t" \
19 "cli" "\n\t" \
20 "wdr" "\n\t" \
21 "sts %0,%1" "\n\t" \
22 "out __SREG__,__tmp_reg__" "\n\t" \
23 "sts %0,%2" "\n\t" \
24 : /* no outputs */ \
25 : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
26 "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
27 "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
28 _BV(WDIE) | (value & 0x07)) ) \
29 : "r0" \
30)
31
32
33void suspend_idle(uint8_t time)
34{
35 cli();
36 set_sleep_mode(SLEEP_MODE_IDLE);
37 sleep_enable();
38 sei();
39 sleep_cpu();
40 sleep_disable();
41}
42
43/* Power down MCU with watchdog timer
44 * wdto: watchdog timer timeout defined in <avr/wdt.h>
45 * WDTO_15MS
46 * WDTO_30MS
47 * WDTO_60MS
48 * WDTO_120MS
49 * WDTO_250MS
50 * WDTO_500MS
51 * WDTO_1S
52 * WDTO_2S
53 * WDTO_4S
54 * WDTO_8S
55 */
56static uint8_t wdt_timeout = 0;
57static void power_down(uint8_t wdto)
58{
59#ifdef PROTOCOL_LUFA
60 if (USB_DeviceState == DEVICE_STATE_Configured) return;
61#endif
62 wdt_timeout = wdto;
63
64 // Watchdog Interrupt Mode
65 wdt_intr_enable(wdto);
66
67 // TODO: more power saving
68 // See PicoPower application note
69 // - I/O port input with pullup
70 // - prescale clock
71 // - BOD disable
72 // - Power Reduction Register PRR
73 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
74 sleep_enable();
75 sei();
76 sleep_cpu();
77 sleep_disable();
78
79 // Disable watchdog after sleep
80 wdt_disable();
81}
82
83void suspend_power_down(void)
84{
85 power_down(WDTO_15MS);
86}
87
88bool suspend_wakeup_condition(void)
89{
90 matrix_power_up();
91 matrix_scan();
92 matrix_power_down();
93 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
94 if (matrix_get_row(r)) return true;
95 }
96 return false;
97}
98
99// run immediately after wakeup
100void suspend_wakeup_init(void)
101{
102 // clear keyboard state
103 clear_keyboard();
104#ifdef BACKLIGHT_ENABLE
105 backlight_init();
106#endif
107}
108
109#ifndef NO_SUSPEND_POWER_DOWN
110/* watchdog timeout */
111ISR(WDT_vect)
112{
113 // compensate timer for sleep
114 switch (wdt_timeout) {
115 case WDTO_15MS:
116 timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
117 break;
118 default:
119 ;
120 }
121}
122#endif
diff --git a/tmk_core/common/avr/suspend_avr.h b/tmk_core/common/avr/suspend_avr.h
new file mode 100644
index 000000000..357102da4
--- /dev/null
+++ b/tmk_core/common/avr/suspend_avr.h
@@ -0,0 +1,27 @@
1#ifndef SUSPEND_AVR_H
2#define SUSPEND_AVR_H
3
4#include <stdint.h>
5#include <stdbool.h>
6#include <avr/sleep.h>
7#include <avr/wdt.h>
8#include <avr/interrupt.h>
9
10
11#define wdt_intr_enable(value) \
12__asm__ __volatile__ ( \
13 "in __tmp_reg__,__SREG__" "\n\t" \
14 "cli" "\n\t" \
15 "wdr" "\n\t" \
16 "sts %0,%1" "\n\t" \
17 "out __SREG__,__tmp_reg__" "\n\t" \
18 "sts %0,%2" "\n\t" \
19 : /* no outputs */ \
20 : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
21 "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
22 "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
23 _BV(WDIE) | (value & 0x07)) ) \
24 : "r0" \
25)
26
27#endif
diff --git a/tmk_core/common/avr/timer.c b/tmk_core/common/avr/timer.c
new file mode 100644
index 000000000..292b41c3a
--- /dev/null
+++ b/tmk_core/common/avr/timer.c
@@ -0,0 +1,117 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <avr/io.h>
19#include <avr/interrupt.h>
20#include <stdint.h>
21#include "timer_avr.h"
22#include "timer.h"
23
24
25// counter resolution 1ms
26// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
27volatile uint32_t timer_count = 0;
28
29void timer_init(void)
30{
31 // Timer0 CTC mode
32 TCCR0A = 0x02;
33
34#if TIMER_PRESCALER == 1
35 TCCR0B = 0x01;
36#elif TIMER_PRESCALER == 8
37 TCCR0B = 0x02;
38#elif TIMER_PRESCALER == 64
39 TCCR0B = 0x03;
40#elif TIMER_PRESCALER == 256
41 TCCR0B = 0x04;
42#elif TIMER_PRESCALER == 1024
43 TCCR0B = 0x05;
44#else
45# error "Timer prescaler value is NOT vaild."
46#endif
47
48 OCR0A = TIMER_RAW_TOP;
49 TIMSK0 = (1<<OCIE0A);
50}
51
52inline
53void timer_clear(void)
54{
55 uint8_t sreg = SREG;
56 cli();
57 timer_count = 0;
58 SREG = sreg;
59}
60
61inline
62uint16_t timer_read(void)
63{
64 uint32_t t;
65
66 uint8_t sreg = SREG;
67 cli();
68 t = timer_count;
69 SREG = sreg;
70
71 return (t & 0xFFFF);
72}
73
74inline
75uint32_t timer_read32(void)
76{
77 uint32_t t;
78
79 uint8_t sreg = SREG;
80 cli();
81 t = timer_count;
82 SREG = sreg;
83
84 return t;
85}
86
87inline
88uint16_t timer_elapsed(uint16_t last)
89{
90 uint32_t t;
91
92 uint8_t sreg = SREG;
93 cli();
94 t = timer_count;
95 SREG = sreg;
96
97 return TIMER_DIFF_16((t & 0xFFFF), last);
98}
99
100inline
101uint32_t timer_elapsed32(uint32_t last)
102{
103 uint32_t t;
104
105 uint8_t sreg = SREG;
106 cli();
107 t = timer_count;
108 SREG = sreg;
109
110 return TIMER_DIFF_32(t, last);
111}
112
113// excecuted once per 1ms.(excess for just timer count?)
114ISR(TIMER0_COMPA_vect)
115{
116 timer_count++;
117}
diff --git a/tmk_core/common/avr/timer_avr.h b/tmk_core/common/avr/timer_avr.h
new file mode 100644
index 000000000..0e85eb101
--- /dev/null
+++ b/tmk_core/common/avr/timer_avr.h
@@ -0,0 +1,42 @@
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#ifndef TIMER_AVR_H
19#define TIMER_AVR_H 1
20
21#include <stdint.h>
22
23#ifndef TIMER_PRESCALER
24# if F_CPU > 16000000
25# define TIMER_PRESCALER 256
26# elif F_CPU > 2000000
27# define TIMER_PRESCALER 64
28# elif F_CPU > 250000
29# define TIMER_PRESCALER 8
30# else
31# define TIMER_PRESCALER 1
32# endif
33#endif
34#define TIMER_RAW_FREQ (F_CPU/TIMER_PRESCALER)
35#define TIMER_RAW TCNT0
36#define TIMER_RAW_TOP (TIMER_RAW_FREQ/1000)
37
38#if (TIMER_RAW_TOP > 255)
39# error "Timer0 can't count 1ms at this clock freq. Use larger prescaler."
40#endif
41
42#endif
diff --git a/tmk_core/common/avr/xprintf.S b/tmk_core/common/avr/xprintf.S
new file mode 100644
index 000000000..0cec70ce2
--- /dev/null
+++ b/tmk_core/common/avr/xprintf.S
@@ -0,0 +1,500 @@
1;---------------------------------------------------------------------------;
2; Extended itoa, puts, printf and atoi (C)ChaN, 2011
3;---------------------------------------------------------------------------;
4
5 // Base size is 152 bytes
6#define CR_CRLF 0 // Convert \n to \r\n (+10 bytes)
7#define USE_XPRINTF 1 // Enable xprintf function (+194 bytes)
8#define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes)
9#define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes)
10#define USE_XATOI 0 // Enable xatoi function (+182 bytes)
11
12
13#if FLASHEND > 0x1FFFF
14#error xitoa module does not support 256K devices
15#endif
16
17.nolist
18#include <avr/io.h> // Include device specific definitions.
19.list
20
21#ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw".
22.macro _LPMI reg
23 lpm \reg, Z+
24.endm
25.macro _MOVW dh,dl, sh,sl
26 movw \dl, \sl
27.endm
28#else // Earlier devices do not have "lpm Rd,Z+" nor "movw".
29.macro _LPMI reg
30 lpm
31 mov \reg, r0
32 adiw ZL, 1
33.endm
34.macro _MOVW dh,dl, sh,sl
35 mov \dl, \sl
36 mov \dh, \sh
37.endm
38#endif
39
40
41
42;---------------------------------------------------------------------------
43; Stub function to forward to user output function
44;
45;Prototype: void xputc (char chr // a character to be output
46; );
47;Size: 12/12 words
48
49.section .bss
50.global xfunc_out ; xfunc_out must be initialized before using this module.
51xfunc_out: .ds.w 1
52.section .text
53
54
55.func xputc
56.global xputc
57xputc:
58#if CR_CRLF
59 cpi r24, 10 ;LF --> CRLF
60 brne 1f ;
61 ldi r24, 13 ;
62 rcall 1f ;
63 ldi r24, 10 ;/
641:
65#endif
66 push ZH
67 push ZL
68 lds ZL, xfunc_out+0 ;Pointer to the registered output function.
69 lds ZH, xfunc_out+1 ;/
70 sbiw ZL, 0 ;Skip if null
71 breq 2f ;/
72 icall
732: pop ZL
74 pop ZH
75 ret
76.endfunc
77
78
79
80;---------------------------------------------------------------------------
81; Direct ROM string output
82;
83;Prototype: void xputs (const char *str_p // rom string to be output
84; );
85
86.func xputs
87.global xputs
88xputs:
89 _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string
901: _LPMI r24
91 cpi r24, 0
92 breq 2f
93 rcall xputc
94 rjmp 1b
952: ret
96.endfunc
97
98
99;---------------------------------------------------------------------------
100; Extended direct numeral string output (32bit version)
101;
102;Prototype: void xitoa (long value, // value to be output
103; char radix, // radix
104; char width); // minimum width
105;
106
107.func xitoa
108.global xitoa
109xitoa:
110 ;r25:r22 = value, r20 = base, r18 = digits
111 clr r31 ;r31 = stack level
112 ldi r30, ' ' ;r30 = sign
113 ldi r19, ' ' ;r19 = filler
114 sbrs r20, 7 ;When base indicates signd format and the value
115 rjmp 0f ;is minus, add a '-'.
116 neg r20 ;
117 sbrs r25, 7 ;
118 rjmp 0f ;
119 ldi r30, '-' ;
120 com r22 ;
121 com r23 ;
122 com r24 ;
123 com r25 ;
124 adc r22, r1 ;
125 adc r23, r1 ;
126 adc r24, r1 ;
127 adc r25, r1 ;/
1280: sbrs r18, 7 ;When digits indicates zero filled,
129 rjmp 1f ;filler is '0'.
130 neg r18 ;
131 ldi r19, '0' ;/
132 ;----- string conversion loop
1331: ldi r21, 32 ;r26 = r25:r22 % r20
134 clr r26 ;r25:r22 /= r20
1352: lsl r22 ;
136 rol r23 ;
137 rol r24 ;
138 rol r25 ;
139 rol r26 ;
140 cp r26, r20 ;
141 brcs 3f ;
142 sub r26, r20 ;
143 inc r22 ;
1443: dec r21 ;
145 brne 2b ;/
146 cpi r26, 10 ;r26 is a numeral digit '0'-'F'
147 brcs 4f ;
148 subi r26, -7 ;
1494: subi r26, -'0' ;/
150 push r26 ;Stack it
151 inc r31 ;/
152 cp r22, r1 ;Repeat until r25:r22 gets zero
153 cpc r23, r1 ;
154 cpc r24, r1 ;
155 cpc r25, r1 ;
156 brne 1b ;/
157
158 cpi r30, '-' ;Minus sign if needed
159 brne 5f ;
160 push r30 ;
161 inc r31 ;/
1625: cp r31, r18 ;Filler
163 brcc 6f ;
164 push r19 ;
165 inc r31 ;
166 rjmp 5b ;/
167
1686: pop r24 ;Flush stacked digits and exit
169 rcall xputc ;
170 dec r31 ;
171 brne 6b ;/
172
173 ret
174.endfunc
175
176
177
178;---------------------------------------------------------------------------;
179; Formatted string output (16/32bit version)
180;
181;Prototype:
182; void __xprintf (const char *format_p, ...);
183; void __xsprintf(char*, const char *format_p, ...);
184; void __xfprintf(void(*func)(char), const char *format_p, ...);
185;
186
187#if USE_XPRINTF
188
189.func xvprintf
190xvprintf:
191 ld ZL, Y+ ;Z = pointer to format string
192 ld ZH, Y+ ;/
193
1940: _LPMI r24 ;Get a format char
195 cpi r24, 0 ;End of format string?
196 breq 90f ;/
197 cpi r24, '%' ;Is format?
198 breq 20f ;/
1991: rcall xputc ;Put a normal character
200 rjmp 0b ;/
20190: ret
202
20320: ldi r18, 0 ;r18: digits
204 clt ;T: filler
205 _LPMI r21 ;Get flags
206 cpi r21, '%' ;Is a %?
207 breq 1b ;/
208 cpi r21, '0' ;Zero filled?
209 brne 23f ;
210 set ;/
21122: _LPMI r21 ;Get width
21223: cpi r21, '9'+1 ;
213 brcc 24f ;
214 subi r21, '0' ;
215 brcs 90b ;
216 lsl r18 ;
217 mov r0, r18 ;
218 lsl r18 ;
219 lsl r18 ;
220 add r18, r0 ;
221 add r18, r21 ;
222 rjmp 22b ;/
223
22424: brtc 25f ;get value (low word)
225 neg r18 ;
22625: ld r24, Y+ ;
227 ld r25, Y+ ;/
228 cpi r21, 'c' ;Is type character?
229 breq 1b ;/
230 cpi r21, 's' ;Is type RAM string?
231 breq 50f ;/
232 cpi r21, 'S' ;Is type ROM string?
233 breq 60f ;/
234 _MOVW r23,r22,r25,r24 ;r25:r22 = value
235 clr r24 ;
236 clr r25 ;
237 clt ;/
238 cpi r21, 'l' ;Is long int?
239 brne 26f ;
240 ld r24, Y+ ;get value (high word)
241 ld r25, Y+ ;
242 set ;
243 _LPMI r21 ;/
24426: cpi r21, 'd' ;Is type signed decimal?
245 brne 27f ;/
246 ldi r20, -10 ;
247 brts 40f ;
248 sbrs r23, 7 ;
249 rjmp 40f ;
250 ldi r24, -1 ;
251 ldi r25, -1 ;
252 rjmp 40f ;/
25327: cpi r21, 'u' ;Is type unsigned decimal?
254 ldi r20, 10 ;
255 breq 40f ;/
256 cpi r21, 'X' ;Is type hexdecimal?
257 ldi r20, 16 ;
258 breq 40f ;/
259 cpi r21, 'b' ;Is type binary?
260 ldi r20, 2 ;
261 breq 40f ;/
262 ret ;abort
26340: push ZH ;Output the value
264 push ZL ;
265 rcall xitoa ;
26642: pop ZL ;
267 pop ZH ;
268 rjmp 0b ;/
269
27050: push ZH ;Put a string on the RAM
271 push ZL
272 _MOVW ZH,ZL, r25,r24
27351: ld r24, Z+
274 cpi r24, 0
275 breq 42b
276 rcall xputc
277 rjmp 51b
278
27960: push ZH ;Put a string on the ROM
280 push ZL
281 rcall xputs
282 rjmp 42b
283.endfunc
284
285
286.func __xprintf
287.global __xprintf
288__xprintf:
289 push YH
290 push YL
291 in YL, _SFR_IO_ADDR(SPL)
292#ifdef SPH
293 in YH, _SFR_IO_ADDR(SPH)
294#else
295 clr YH
296#endif
297 adiw YL, 5 ;Y = pointer to arguments
298 rcall xvprintf
299 pop YL
300 pop YH
301 ret
302.endfunc
303
304
305#if USE_XSPRINTF
306
307.func __xsprintf
308putram:
309 _MOVW ZH,ZL, r15,r14
310 st Z+, r24
311 _MOVW r15,r14, ZH,ZL
312 ret
313.global __xsprintf
314__xsprintf:
315 push YH
316 push YL
317 in YL, _SFR_IO_ADDR(SPL)
318#ifdef SPH
319 in YH, _SFR_IO_ADDR(SPH)
320#else
321 clr YH
322#endif
323 adiw YL, 5 ;Y = pointer to arguments
324 lds ZL, xfunc_out+0 ;Save registered output function
325 lds ZH, xfunc_out+1 ;
326 push ZL ;
327 push ZH ;/
328 ldi ZL, lo8(pm(putram));Set local output function
329 ldi ZH, hi8(pm(putram));
330 sts xfunc_out+0, ZL ;
331 sts xfunc_out+1, ZH ;/
332 push r15 ;Initialize pointer to string buffer
333 push r14 ;
334 ld r14, Y+ ;
335 ld r15, Y+ ;/
336 rcall xvprintf
337 _MOVW ZH,ZL, r15,r14 ;Terminate string
338 st Z, r1 ;
339 pop r14 ;
340 pop r15 ;/
341 pop ZH ;Restore registered output function
342 pop ZL ;
343 sts xfunc_out+0, ZL ;
344 sts xfunc_out+1, ZH ;/
345 pop YL
346 pop YH
347 ret
348.endfunc
349#endif
350
351
352#if USE_XFPRINTF
353.func __xfprintf
354.global __xfprintf
355__xfprintf:
356 push YH
357 push YL
358 in YL, _SFR_IO_ADDR(SPL)
359#ifdef SPH
360 in YH, _SFR_IO_ADDR(SPH)
361#else
362 clr YH
363#endif
364 adiw YL, 5 ;Y = pointer to arguments
365 lds ZL, xfunc_out+0 ;Save registered output function
366 lds ZH, xfunc_out+1 ;
367 push ZL ;
368 push ZH ;/
369 ld ZL, Y+ ;Set output function
370 ld ZH, Y+ ;
371 sts xfunc_out+0, ZL ;
372 sts xfunc_out+1, ZH ;/
373 rcall xvprintf
374 pop ZH ;Restore registered output function
375 pop ZL ;
376 sts xfunc_out+0, ZL ;
377 sts xfunc_out+1, ZH ;/
378 pop YL
379 pop YH
380 ret
381.endfunc
382#endif
383
384#endif
385
386
387
388;---------------------------------------------------------------------------
389; Extended numeral string input
390;
391;Prototype:
392; char xatoi ( /* 1: Successful, 0: Failed */
393; const char **str, /* pointer to pointer to source string */
394; long *res /* result */
395; );
396;
397
398
399#if USE_XATOI
400.func xatoi
401.global xatoi
402xatoi:
403 _MOVW r1, r0, r23, r22
404 _MOVW XH, XL, r25, r24
405 ld ZL, X+
406 ld ZH, X+
407 clr r18 ;r21:r18 = 0;
408 clr r19 ;
409 clr r20 ;
410 clr r21 ;/
411 clt ;T = 0;
412
413 ldi r25, 10 ;r25 = 10;
414 rjmp 41f ;/
41540: adiw ZL, 1 ;Z++;
41641: ld r22, Z ;r22 = *Z;
417 cpi r22, ' ' ;if(r22 == ' ') continue
418 breq 40b ;/
419 brcs 70f ;if(r22 < ' ') error;
420 cpi r22, '-' ;if(r22 == '-') {
421 brne 42f ; T = 1;
422 set ; continue;
423 rjmp 40b ;}
42442: cpi r22, '9'+1 ;if(r22 > '9') error;
425 brcc 70f ;/
426 cpi r22, '0' ;if(r22 < '0') error;
427 brcs 70f ;/
428 brne 51f ;if(r22 > '0') cv_start;
429 ldi r25, 8 ;r25 = 8;
430 adiw ZL, 1 ;r22 = *(++Z);
431 ld r22, Z ;/
432 cpi r22, ' '+1 ;if(r22 <= ' ') exit;
433 brcs 80f ;/
434 cpi r22, 'b' ;if(r22 == 'b') {
435 brne 43f ; r25 = 2;
436 ldi r25, 2 ; cv_start;
437 rjmp 50f ;}
43843: cpi r22, 'x' ;if(r22 != 'x') error;
439 brne 51f ;/
440 ldi r25, 16 ;r25 = 16;
441
44250: adiw ZL, 1 ;Z++;
443 ld r22, Z ;r22 = *Z;
44451: cpi r22, ' '+1 ;if(r22 <= ' ') break;
445 brcs 80f ;/
446 cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20;
447 brcs 52f ;
448 subi r22, 0x20 ;/
44952: subi r22, '0' ;if((r22 -= '0') < 0) error;
450 brcs 70f ;/
451 cpi r22, 10 ;if(r22 >= 10) {
452 brcs 53f ; r22 -= 7;
453 subi r22, 7 ; if(r22 < 10)
454 cpi r22, 10 ;
455 brcs 70f ;}
45653: cp r22, r25 ;if(r22 >= r25) error;
457 brcc 70f ;/
45860: ldi r24, 33 ;r21:r18 *= r25;
459 sub r23, r23 ;
46061: brcc 62f ;
461 add r23, r25 ;
46262: lsr r23 ;
463 ror r21 ;
464 ror r20 ;
465 ror r19 ;
466 ror r18 ;
467 dec r24 ;
468 brne 61b ;/
469 add r18, r22 ;r21:r18 += r22;
470 adc r19, r24 ;
471 adc r20, r24 ;
472 adc r21, r24 ;/
473 rjmp 50b ;repeat
474
47570: ldi r24, 0
476 rjmp 81f
47780: ldi r24, 1
47881: brtc 82f
479 clr r22
480 com r18
481 com r19
482 com r20
483 com r21
484 adc r18, r22
485 adc r19, r22
486 adc r20, r22
487 adc r21, r22
48882: st -X, ZH
489 st -X, ZL
490 _MOVW XH, XL, r1, r0
491 st X+, r18
492 st X+, r19
493 st X+, r20
494 st X+, r21
495 clr r1
496 ret
497.endfunc
498#endif
499
500
diff --git a/tmk_core/common/avr/xprintf.h b/tmk_core/common/avr/xprintf.h
new file mode 100644
index 000000000..59c6f2531
--- /dev/null
+++ b/tmk_core/common/avr/xprintf.h
@@ -0,0 +1,111 @@
1/*---------------------------------------------------------------------------
2 Extended itoa, puts and printf (C)ChaN, 2011
3-----------------------------------------------------------------------------*/
4
5#ifndef XPRINTF_H
6#define XPRINTF_H
7
8#include <inttypes.h>
9#include <avr/pgmspace.h>
10
11#ifdef __cplusplus
12extern "C" {
13#endif
14
15extern void (*xfunc_out)(uint8_t);
16#define xdev_out(func) xfunc_out = (void(*)(uint8_t))(func)
17
18/* This is a pointer to user defined output function. It must be initialized
19 before using this modle.
20*/
21
22void xputc(char chr);
23
24/* This is a stub function to forward outputs to user defined output function.
25 All outputs from this module are output via this function.
26*/
27
28
29/*-----------------------------------------------------------------------------*/
30void xputs(const char *string_p);
31
32/* The string placed in the ROM is forwarded to xputc() directly.
33*/
34
35
36/*-----------------------------------------------------------------------------*/
37void xitoa(long value, char radix, char width);
38
39/* Extended itoa().
40
41 value radix width output
42 100 10 6 " 100"
43 100 10 -6 "000100"
44 100 10 0 "100"
45 4294967295 10 0 "4294967295"
46 4294967295 -10 0 "-1"
47 655360 16 -8 "000A0000"
48 1024 16 0 "400"
49 0x55 2 -8 "01010101"
50*/
51
52
53/*-----------------------------------------------------------------------------*/
54#define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__)
55#define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__)
56#define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__)
57
58void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */
59void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */
60void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */
61
62/* Format string is placed in the ROM. The format flags is similar to printf().
63
64 %[flag][width][size]type
65
66 flag
67 A '0' means filled with '0' when output is shorter than width.
68 ' ' is used in default. This is effective only numeral type.
69 width
70 Minimum width in decimal number. This is effective only numeral type.
71 Default width is zero.
72 size
73 A 'l' means the argument is long(32bit). Default is short(16bit).
74 This is effective only numeral type.
75 type
76 'c' : Character, argument is the value
77 's' : String placed on the RAM, argument is the pointer
78 'S' : String placed on the ROM, argument is the pointer
79 'd' : Signed decimal, argument is the value
80 'u' : Unsigned decimal, argument is the value
81 'X' : Hexdecimal, argument is the value
82 'b' : Binary, argument is the value
83 '%' : '%'
84
85*/
86
87
88/*-----------------------------------------------------------------------------*/
89char xatoi(char **str, long *ret);
90
91/* Get value of the numeral string.
92
93 str
94 Pointer to pointer to source string
95
96 "0b11001010" binary
97 "0377" octal
98 "0xff800" hexdecimal
99 "1250000" decimal
100 "-25000" decimal
101
102 ret
103 Pointer to return value
104*/
105
106#ifdef __cplusplus
107}
108#endif
109
110#endif
111