Why is my AVR ATmega32 assembly code for keypad functionality not working

88 Views Asked by At

Firstly, I am extremely sorry if I donot know how to pose a question correctly. It's my first time using this forum for guidance! I have to convert a 4x4 keypad matrix AVR assembly code into 4x3 and this has to be done via interrupts. So far, this is what i have done:

.INCLUDE  "M32DEF.INC"

.org  0x00
jmp main

.org 0x50
main:

.EQU  KEY_PORT  =  PORTC
.EQU  KEY_PIN  =  PINC
.EQU  KEY_DDR  =  DDRC

.EQU  LCD_DPRT  =  PORTA
.EQU  LCD_DDDR  =  DDRA
.EQU  LCD_DPIN  =  PINA
.EQU  LCD_CPRT  =  PORTB
.EQU  LCD_CDDR  =  DDRB
.EQU  LCD_CPIN  =  PINB
.EQU  LCD_RS  =  0
.EQU  LCD_RW  =  1
.EQU  LCD_EN  =  2


LDI  R20,  HIGH  (RAMEND) 
OUT  SPH,R20
LDI  R20,  LOW  (RAMEND) 
OUT  SPL,R20
;  ascii  code  for  keypressed  displayed  on  PORTD 
LDI  R21,  0xFF
OUT  DDRA,R21  ; port a output to lcd
;  PC0  – PC3  rows
;  PC4  – PC6  columns
LDI  R20,  0xF0  //portc  0-3  input  pins 
OUT  KEY_DDR,  R20

GroundAllColumns:
LDI  R20,  0b00001110  //  portc  0-3  display  111 
OUT  KEY_PORT,  R20

LDI  R21,0xFF;
OUT  LCD_DDDR,  R21  ;LCD  data  port  is  output 
OUT  LCD_CDDR,  R21 ;  A,B  PORT  AS  OUTPUT 
CBI  LCD_CPRT,LCD_EN
CALL  DELAY_2ms  ;wait  for  power  on 
LDI  R16,0x38  ;  FOR  7X5  DISPLAY
CALL  CMNDWRT  ;call  command  function 
CALL  DELAY_2ms  ;wait  2  ms
LDI  R16,0x0E  ;display  on,  cursor  on 
CALL  CMNDWRT  ;call  command  function 
LDI  R16,0x01  ;clear  LCD
CALL CMNDWRT 
CALL DELAY_2ms
LDI  R16,0x06  ;  INCREMENT  CURSOR 
CALL CMNDWRT
LDI  R16,0x84  ;  INCREMENT  CURSOR  IST  LINE  4TH  COLUMN 
CALL CMNDWRT

LDI  R16,  'F' 
CALL DATAWRT 
LDI  R16,  'A' 
CALL DATAWRT

LDI  R16,  'S' 
CALL DATAWRT 
LDI  R16,  'T' 
CALL DATAWRT

LDI  R16,0xC3  ;  INCREMENT  CURSOR  2ND  LINE  3RD  COLUMN 
CALL CMNDWRT
LDI  R16,  '0' 
CALL DATAWRT

here: rjmp here

KPD_ISR:
LDI  R21,  0b01111111 
OUT  KEY_PORT,R21 
NOP
IN  R21,KEY_PIN

ANDI  R21,0x0F 
CPI  R21,0x0F 
BRNE COL1

LDI  R21,  0b10111111 
OUT  KEY_PORT,  R21 
NOP
IN  R21,  KEY_PIN 
ANDI  R21,0x0F 
CPI  R21,0x0F 
BRNE COL2

LDI  R21,  0b11011111 
OUT  KEY_PORT,  R21 
NOP
IN  R21,  KEY_PIN 
ANDI  R21,0x0F 
CPI  R21,0x0F 
BRNE COL3

COL1:
LDI  R30,  LOW(KCODE0<<1) 
LDI  R31,  HIGH(KCODE0<<1)
RJMP  Find 
COL2:
LDI  R30,  LOW(KCODE1<<1) 
LDI  R31,  HIGH(KCODE1<<1)
RJMP  Find 
COL3:
LDI  R30,  LOW(KCODE2<<1) 
LDI  R31,  HIGH(KCODE2<<1)
RJMP  Find 

Find:
LSR R21
BRCC  Match 
LPM  R20,  Z+
RJMP  Find MATCH:
LPM  R20,  Z

ldi  r17,0x0f 
in  r16,pinc 
andi  r16,0x0f 
cp  r16,r17 
breq  kpd_isr

OUT  PORTA,  R20
mov  r16,r20
call  datawrt  ;  here call  BDELAY

rjmp  KPD_ISR


.ORG  0x300
KCODE0: .DB  '7',  '8',  '9' ;col1
KCODE1: .DB  '4',  '5',  '6'
KCODE2: .DB  '1',  '2',  '3'
KCODE3: .DB  'c',  '0',  '='

I get my initialized output on the LCD in my proteus simulation, but whenever I press anything on the keypad it doesn't register on the LCD. I can see from my simulation that my columns from pins p4-p6 are set which im not sure should be the case: My proteus simulation:

I adjusted the code provided in my manual, but as I am learning I'm not sure at all where I went wrong. Also, i remember that interrupt service routines require a vector table (IVT) and you call them from their designated memory locations in the IVT. In the code I was provided, there was an ISR for the keypad button pressing but no IVT set. Could that be the problem?

1

There are 1 best solutions below

2
On

Your code does not contain any ISR function. The ISR function is activated by an interrupt. You don't have any interrupt enabled and you don't have a jump set to the relevant ISR function.

KPD_ISR is not an ISR, and is not a function. The function is called by the CALL instruction and must end with the RET instruction. The ISR function is called by an interrupt and must end with an RETI instruction. In order for the activated interrupt to call the ISR function, there must be a jump to the ISR at the appropriate place in the IVT.

And one more important thing. The ISR must not cause any change to the state of the processor after completion. So it has to take care of saving and restoring all used registers including SREG.

For the next ISR, it should be as short as possible. In no case should it contain a long-lasting code, writing on the display in your code.

Please read some tutorial, for example here