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 LED_PORT 7
@ -8,28 +10,33 @@ lm35_port: .byte 0
.section .text
.global init
.global blink
.global float_test
.global lm35_init
.global lm35_read
init:
.global led_init
.global led_enable
.global led_disable
led_init:
sbi DDRD, LED_PORT
ret
analog_pin_mode_input:
; sets analog pin as input
; input: r24 - number of pin in DDRC I/O register
; output: -
led_enable:
sbi PORTD, LED_PORT
ret
led_disable:
cbi PORTD, LED_PORT
ret
; r31 mask to set 0 in I/O register
.macro pin_mode_input port
; sets analog port as input
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)
mov r30, r24
mov r30, \port
convert:
lsl r31 ; logic shift left ~ r31 * 2
dec r30
@ -42,52 +49,28 @@ end_convert:
in r30, DDRC
and r30, r31 ; applying mask (11111111 and 11110111 = 11110111)
out DDRC, r30
.endm
ret
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
.macro adc_read port, res_high, res_low
ldi r30, 0b00000000
sts PRR, r30
; first two bits are for the ref voltage
; 11 means using internal 1.1v atmega voltage for adc
; last three bits are for the analog port number
ldi r30, 0b11000000
lds r24, lm35_port
or r30, r24
or r30, \port
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
sts ADCSRA, r30
@ -99,30 +82,48 @@ wait_adc:
cpi r31, 0
brne wait_adc
lds r24, ADCL
lds r25, ADCH
lds \res_low, ADCL
lds \res_high, ADCH
; clearing unused bits to be sure they're zero
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
; divident_low - quotient
ldi r30, 0
division:
cpi r24, 10
cpi \divident_low, 10
brlo division_low_end ; <
continue_division:
sbiw r24, 10
sbiw \divident_low, 10
inc r30
rjmp division
division_low_end:
cpi r25, 0
cpi \divident_high, 0
brne continue_division
cpi r24, 5
cpi \divident_low, 5
brlo not_inc ; <
inc r30
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
adiw r24, 2 ; due to LM35 formula (2C to 150C)
@ -130,17 +131,3 @@ not_inc:
clr r1 ; c requirement
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" {
void init();
void blink();
float float_test();
// Copyright 2021 KoroLion (https://github.com/KoroLion)
extern "C" {
void lm35_init(uint8_t port);
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() {
Serial.begin(9600);
lm35_init(A3);
// init();
led_init();
}
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();
printPortsStatus();
if (t >= 30) {
led_enable();
} else {
led_disable();
}
Serial.println(t);
//Serial.print(" vs ");
}