Major refactoring

This commit is contained in:
KoroLion 2021-01-22 02:24:05 +03:00
parent 218e7701e1
commit 76c649475a
3 changed files with 110 additions and 160 deletions

37
src/avr_asm_demo.s Normal file
View File

@ -0,0 +1,37 @@
.global init
.global blink
.global float_test
float_test:
ldi r25, 0b00111110
ldi r24, 0b00100000
ldi r23, 0b01000000
ldi r22, 0b00000000
clr r1
ret
blink:
ldi r20, 250
call delay_n_ms
ldi r20, 250
call delay_n_ms
sbi PORTD, LED_PORT ; high
ldi r20, 250
call delay_n_ms
cbi PORTD, LED_PORT ; low
ret
delay_n_ms:
; delay for ~r20 * 1ms. r20, r30, and r31 are modified.
; 1 ms ~ 16000 cycles at 16MHz.
; The basic loop takes about 5 cycles, so we need about 3000 loops.
ldi r31, 3000 >> 8 ; high byte of the 3000
ldi r30, 3000 & 255 ; low byte of the 3000
delaylp:
sbiw r30, 1 ; sub word r30 1
brne delaylp ; jne delaylp
subi r20, 1
brne delay_n_ms
ret

View File

@ -1,3 +1,5 @@
; Copyright 2021 KoroLion (https://github.com/KoroLion)
#define __SFR_OFFSET 0 #define __SFR_OFFSET 0
#define LED_PORT 7 #define LED_PORT 7
@ -8,28 +10,33 @@ lm35_port: .byte 0
.section .text .section .text
.global init
.global blink
.global float_test
.global lm35_init .global lm35_init
.global lm35_read .global lm35_read
init: .global led_init
sbi DDRD, LED_PORT .global led_enable
.global led_disable
led_init:
sbi DDRD, LED_PORT
ret ret
analog_pin_mode_input: led_enable:
; sets analog pin as input sbi PORTD, LED_PORT
; input: r24 - number of pin in DDRC I/O register ret
; output: -
; r31 mask to set 0 in I/O register led_disable:
cbi PORTD, LED_PORT
ret
.macro pin_mode_input port
; sets analog port as input
ldi r31, 1 ; means port 0 ldi r31, 1 ; means port 0
cpi r24, 0 cpi \port, 0
breq end_convert ; = 0 => no need to convert (already set mask to port 0) breq end_convert ; = 0 => no need to convert (already set mask to port 0)
mov r30, r24 mov r30, \port
convert: convert:
lsl r31 ; logic shift left ~ r31 * 2 lsl r31 ; logic shift left ~ r31 * 2
dec r30 dec r30
@ -42,41 +49,9 @@ end_convert:
in r30, DDRC in r30, DDRC
and r30, r31 ; applying mask (11111111 and 11110111 = 11110111) and r30, r31 ; applying mask (11111111 and 11110111 = 11110111)
out DDRC, r30 out DDRC, r30
.endm
ret .macro adc_read port, res_high, res_low
lm35_init:
; args: r24 to r20, where r24 is the lowest
subi r24, 14 ; because A0 is D14
call analog_pin_mode_input
sts lm35_port, r24
ret
float_test:
ldi r25, 0b00111110
ldi r24, 0b00100000
ldi r23, 0b01000000
ldi r22, 0b00000000
clr r1
ret
blink:
ldi r20, 250
call delay_n_ms
ldi r20, 250
call delay_n_ms
sbi PORTD, LED_PORT ; high
ldi r20, 250
call delay_n_ms
cbi PORTD, LED_PORT ; low
ret
lm35_read:
; return: r24 to r19, where r24 is the lowest
cli ; forbids interruptions
ldi r30, 0b00000000 ldi r30, 0b00000000
sts PRR, r30 sts PRR, r30
@ -84,10 +59,18 @@ lm35_read:
; 11 means using internal 1.1v atmega voltage for adc ; 11 means using internal 1.1v atmega voltage for adc
; last three bits are for the analog port number ; last three bits are for the analog port number
ldi r30, 0b11000000 ldi r30, 0b11000000
lds r24, lm35_port or r30, \port
or r30, r24
sts ADMUX, r30 sts ADMUX, r30
; last 3 bits (111 means 128)
; ADC Prescaler Select Bits (ADPS): ADPS2, ADPS1 and ADPS0 bits are used to set circuit clock frequency.
; For ADC circuitry to work at its maximum resolution needs to be supplied with 50 kHz to 200 kHz frequency as per the datasheet;
; but the system clock will be generally higher (8 MHz, 10 MHz, 16 MHz etc).
; To reduce it to required frequency we use ADC prescaler bits. Suppose we have system clock with frequency 10Mhz (10000000 Hz) and set division factor to 64,
; then ADC clock frequency is 10000000/64 = 156250Hz = 156.25 KHz, which is between 50 to 200 KHz as mentioned in the datasheet.
; (http://www.robotplatform.com/knowledge/ADC/adc_tutorial_2.html)
;
; 16 MHz / 128 = 16000000 Hz / 128 = 125000 Hz = 125 KHz => OK!
ldi r30, 0b11000111 ldi r30, 0b11000111
sts ADCSRA, r30 sts ADCSRA, r30
@ -99,30 +82,48 @@ wait_adc:
cpi r31, 0 cpi r31, 0
brne wait_adc brne wait_adc
lds r24, ADCL lds \res_low, ADCL
lds r25, ADCH lds \res_high, ADCH
; clearing unused bits to be sure they're zero ; clearing unused bits to be sure they're zero
ldi r31, 0b00000011 ldi r31, 0b00000011
and r25, r31 and \res_high, r31
.endm
; r25 high, r24 low - divident and then quotient .macro divw10 divident_high, divident_low
; r30 - res ; r30 - res
; divident_low - quotient
ldi r30, 0 ldi r30, 0
division: division:
cpi r24, 10 cpi \divident_low, 10
brlo division_low_end ; < brlo division_low_end ; <
continue_division: continue_division:
sbiw r24, 10 sbiw \divident_low, 10
inc r30 inc r30
rjmp division rjmp division
division_low_end: division_low_end:
cpi r25, 0 cpi \divident_high, 0
brne continue_division brne continue_division
cpi r24, 5 cpi \divident_low, 5
brlo not_inc ; < brlo not_inc ; <
inc r30 inc r30
not_inc: not_inc:
.endm
lm35_init:
; r25:r24 is the first arg
subi r24, 14 ; because A0 is D14
pin_mode_input r24
sts lm35_port, r24
ret
lm35_read:
cli ; forbids interruptions
lds r24, lm35_port
adc_read r24, r25, r24
divw10 r25, r24
mov r24, r30 ; uint8_t return value mov r24, r30 ; uint8_t return value
adiw r24, 2 ; due to LM35 formula (2C to 150C) adiw r24, 2 ; due to LM35 formula (2C to 150C)
@ -130,17 +131,3 @@ not_inc:
clr r1 ; c requirement clr r1 ; c requirement
ret ret
delay_n_ms:
; delay for ~r20 * 1ms. r20, r30, and r31 are modified.
; 1 ms ~ 16000 cycles at 16MHz.
; The basic loop takes about 5 cycles, so we need about 3000 loops.
ldi r31, 3000 >> 8 ; high byte of the 3000
ldi r30, 3000 & 255 ; low byte of the 3000
delaylp:
sbiw r30, 1 ; sub word r30 1
brne delaylp ; jne delaylp
subi r20, 1
brne delay_n_ms
ret

View File

@ -1,102 +1,28 @@
extern "C" { // Copyright 2021 KoroLion (https://github.com/KoroLion)
void init();
void blink();
float float_test();
extern "C" {
void lm35_init(uint8_t port); void lm35_init(uint8_t port);
uint8_t lm35_read(); uint8_t lm35_read();
void led_init();
void led_enable();
void led_disable();
} }
#define UNKNOWN_PIN 0xFF
uint8_t getPinMode(uint8_t pin)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
// I don't see an option for mega to return this, but whatever...
if (NOT_A_PIN == port) return UNKNOWN_PIN;
// Is there a bit we can check?
if (0 == bit) return UNKNOWN_PIN;
// Is there only a single bit set?
if (bit & bit - 1) return UNKNOWN_PIN;
volatile uint8_t *reg, *out;
reg = portModeRegister(port);
out = portOutputRegister(port);
if (*reg & bit)
return OUTPUT;
else if (*out & bit)
return INPUT_PULLUP;
else
return INPUT;
}
void printPortsStatus() {
Serial.print(getPinMode(A0));
Serial.print(getPinMode(A1));
Serial.print(getPinMode(A2));
Serial.print(getPinMode(A3));
Serial.print(getPinMode(A4));
Serial.print(getPinMode(A5));
Serial.println();
}
/*
ADC Prescaler Select Bits (ADPS): ADPS2, ADPS1 and ADPS0 bits are used to set circuit clock frequency.
For ADC circuitry to work at its maximum resolution needs to be supplied with 50 kHz to 200 kHz frequency as per the datasheet;
but the system clock will be generally higher (8 MHz, 10 MHz, 16 MHz etc).
To reduce it to required frequency we use ADC prescaler bits. Suppose we have system clock with frequency 10Mhz (10000000 Hz) and set division factor to 64,
then ADC clock frequency is 10000000/64 = 156250Hz = 156.25 KHz, which is between 50 to 200 KHz as mentioned in the datasheet.
(http://www.robotplatform.com/knowledge/ADC/adc_tutorial_2.html)
16 MHz / 128 = 16000000 Hz / 128 = 125000 Hz = 125 KHz => OK!
*/
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
lm35_init(A3); lm35_init(A3);
led_init();
// init();
} }
void loop() { void loop() {
// blink();
/*ADMUX = 0b01000011;
PRR = 0b00000000;
ADCSRA = 0b11000111;
while ((ADCSRA & 0b01000000) != 0);
short k = ADC;*/
// max value = 1023
// ref voltage is 1.1 V
// 1023 - max byte value
// +2 to 150, 10 mv/C
// k / 255 * 1.1 * 1000 / 10 + 2
// Serial.println((float)k * 0.43137254 + 2);
// pinMode(A3, OUTPUT);
/*float *f = malloc(sizeof(f));
*f = float_test();
for (int i = 0; i < 4; i++) {
Serial.print(((unsigned char*)f)[i]);
Serial.print(" ");
}
Serial.print(" => ");
Serial.print(*f, 8);
Serial.println();*/
// uint16_t k = read_temp(A3);
// Serial.println((float)k / 1023 * 1.1 * 1000 / 10 + 2);
// Serial.println((float)k * 0.10752688 + 2);
uint8_t t = lm35_read(); uint8_t t = lm35_read();
printPortsStatus(); if (t >= 30) {
led_enable();
} else {
led_disable();
}
Serial.println(t); Serial.println(t);
//Serial.print(" vs ");
} }