diff --git a/src/avr_asm_demo.s b/src/avr_asm_demo.s new file mode 100644 index 0000000..33fcb13 --- /dev/null +++ b/src/avr_asm_demo.s @@ -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 \ No newline at end of file diff --git a/src/avr_asm_lib/avr_asm_lib.S b/src/avr_asm_lib/avr_asm_lib.S index 080d3b6..8cac3ad 100644 --- a/src/avr_asm_lib/avr_asm_lib.S +++ b/src/avr_asm_lib/avr_asm_lib.S @@ -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 diff --git a/src/avr_asm_lib/avr_asm_lib.ino b/src/avr_asm_lib/avr_asm_lib.ino index 39ca17b..9382372 100644 --- a/src/avr_asm_lib/avr_asm_lib.ino +++ b/src/avr_asm_lib/avr_asm_lib.ino @@ -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 "); }