MPLAB, trying to clear a bit but it remains 1 - interrupt

I'm using MPLAB to program PIC16F84A for my project. I have an assembly code where RB4-7 bits are connected to buttons and hence used as inputs. An interrupt subroutine is implemented to handle any new interrupt (when a button is pressed). Everything works fine, when a button is pressed the pic goes to the specified subroutine. But now when I'm in the subroutine I have to clear the flag (INTCON - RBIF) but it's not being cleared, yet clearing any other bit in the INTCON register works fine. So what should I do?
Here is my code:
ORG 0X00
GOTO START
ORG 0x04
BTFSC INTCON,RBIF
GOTO RBX_INT
START CLRF PORTA
MOVLW B'10001000'
MOVWF INTCON
BSF STATUS,RP0
CLRF TRISA
MOVLW B'11110000'
MOVWF TRISB
MOVLW B'10000111'
MOVWF OPTION_REG
BCF STATUS,RP0
MAIN GOTO MAIN
And this is my subroutine:
RBX_INT BCF INTCON,RBIF
MOVLW D'156'
CALL DELAY
RETFIE

You should clear the bit right before you return from interrupt, otherwise a new interrupt can already happen while in the delay loop and RBIF will be cleared again. This happens because buttons bounce ( https://en.wikipedia.org/wiki/Switch#Contact_bounce ).
Also, the datasheet states:
The input pins (of RB7:RB4)
are compared with the old value latched on the last
read of PORTB. The “mismatch” outputs of RB7:RB4
are OR’ed together to generate the RB Port Change
Interrupt with flag bit RBIF (INTCON<0>).
This means you have to read PORTB before clearing RBIF to update the latched value.
RBX_INT
MOVFW PORTB ;Read PORTB to update the latch.
MOVLW D'156'
CALL DELAY
BCF INTCON,RBIF ;Clear interrupt flag as close as possible to RETFIE.
RETFIE
Also, you should read up about context saving/restoring for interrupt service routines. For this example it matters not, because the main loop is doing nothing but because a interrupt can happen at any moment it should take care to save all registers and resources it uses and restore them before exiting the interrupt to prevent corrupting any data/state from the main codepath.
See section
6.9
Context Saving During Interrupts
In the PIC16F84A datasheet.

Related

How often should you send the bits of a serial dataframe so that it is recognised as such by RCREG SFR in MPLABX?

I am attempting to simulate the PIC18F458 receiving a byte (i.e., ASCII 'Z', 0x5A) through the RX pin, using a SCL file (see below) in MPLAB X v.5.05.
testbench for "pic18f458" is
begin
process is
begin
loop
RX <= '0';
wait for 104 us;
RX <= '0';
wait for 104 us;
RX <= '1';
wait for 104 us;
RX <= '0';
wait for 1042 us;
RX <= '1';
wait for 104 us;
RX <= '1';
wait for 104 us;
RX <= '0';
wait for 104 us;
RX <= '1';
wait for 104 us;
RX <= '0';
wait for 104 us;
RX <= '1';
wait for 104 us;
end loop;
wait;
end process;
end testbench;
Although, I can see that the data is being injected onto the pin, I do not see it being captured within the RCREG register. (Please see images of RX pin waveform and RCREG output below).
RX Pin Waveform output
RCREG SFR
The code is written so that the bits are transferred at 9600 bps and assumes that XTAL = 10 MHz (see code below).
ORG 0000H ; burn into ROM starting at 0
MOVLW B'10010000' ; load wreg with 0x90
MOVWF RCSTA ; enable receive and serial port itself
MOVLW D'15' ; load wreg 0xF
MOVWF SPBRG ; 9600 bps (Fosc / (64 * S[peed) - 1)
BSF TRISC, RX ; make RX pin of PORTC an input pin
CLRF TRISB ; make PORTB an output port
; get a byte from the serial port and place it on PORTB
R1 BTFSS PIR1, RCIF ; check for ready
BRA R1 ; stay in loop
MOVFF RCREG, PORTB ; send value to PORTB
BRA R1 ; keep doing that
END
Therefore, I was wondering at what intervals should I send the bits within the SCL file, so that it can be recognised as a dataframe of bits transmitted at 9600 bps.
My current assumption is that each bit of the frame consisting of a start bit, 8-bit data and a stop bit, should be transmitted every 104us.
However, this is not providing the desired effect, in terms of the RCREG registering the data on the RX pin.
Therefore, I would appreciate any insight that anyone can provide with regards to the correct value(s) to use, as this is my first time trying to do this.
The Microchip MPLAB simulation tool is an incomplete representation of the controller functionality. The available models of functional blocks like the UART do not seem to sample the simulated input pin states as described in the data sheet.
The UART simulation model supports a "register injection" method to change the internal state of the model to receive data on a byte by byte basis.
You could open a support case with Microchip and ask if your approach is even possible.

Stack Overflow Pushing Return Address of Interrupt PIC 16F628A

can someone help me?
I'm new to pic programming, what I'm trying to do is make bit 3 of port b turn on as long as bit 0 and 7 are 1, main is bit 0. if bit 0 is not 1 output, bit 3, is 0. The bit 3 is turning on, but when I change the bit 0 the bit 3 doesn't change to off (0).
I'm using INTCON REGISTER.
Here's my code:
#include "p16f628a.inc"
; CONFIG
__config 0x3F18
; __CONFIG _FOSC_INTOSCIO & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _CP_OFF
LIST P=16F628A ;DECLARAR EL PIC
RADIX HEX ;DECLARAR QUE SE TRABAJARA EN HEXADECIMAL
STATUS EQU 0x03
PORTA EQU 0X05
PORTB EQU 0X06
CMCON EQU 0X1F
ORG 0X00 ;DECLARAR DONDE INICIARA
GOTO CONF
ORG 0X04
GOTO INTERRUPCIONES
ORG 0X08 ;BRINCAR REGISTROS DE MEMORIA
CONF
BSF CMCON, 0
BSF CMCON, 1
BSF CMCON, 2 ; ANALOG A DIGITAL
BSF STATUS, 5
MOVLW 0XFF
MOVWF PORTA
MOVLW 0x81
MOVWF PORTB
BCF STATUS,5
BSF INTCON,3
BSF INTCON,4
BSF INTCON,7
MAIN
BCF PORTB,3
GOTO MAIN
INTERRUPCIONES
BCF INTCON,GIE
BTFSC INTCON,INTF
GOTO TEMPERATURA
TEMP
BSF INTCON,GIE
BCF INTCON,INTF
RETFIE
TEMPERATURA
BTFSC PORTB,7
BSF PORTB,3
BSF INTCON,GIE
GOTO TEMP
END
If I understand correct; you want to set bit 3 of PORTB to 1 whenever the bit 0 or bit 7 goes high, but bit 0 is superior I mean it has higher priority over the bit 7. In the light of this information we can make the truth table as following:
RB0 (INT0)
RB7
RB3 (output)
0
0
0
0
1 (ignore)
0
1
0 (ignore)
1
1
1
1
But my question here is: What is the role of bit 7 if it doesn't have any affect on the output since the bit 0 override it in any case? Please let me know that.
So according to the table the output will set to 1 only if the higher priority interrupt input (RB0) is 1. For the rest the output remains 0. Correct me if I miss something.
Let's implement this logic into your existing code. By the way I've also noted that you've set the RB Port change interrupt but didn't service it. I will only write the related part with some optimizations.
INTERRUPCIONES
; BCF INTCON,GIE ; No need to do this since the hardware does this automatically
BTFSS INTCON,INTF
GOTO DONE ; Not INTF interrupt simply skip
BCF INTCON,INTF ; Better clear this flag as soon as you start to service it
BSF PORTB,0 ; High priority input goes 1 hence no more questions to setting the output as 1
; Check for PORTB on change interrupt
BTFSS INTCON,RBIF
GOTO DONE ; Not RBIF interrupt simply skip
BCF INTCON,RBIF ; First of all clear the interrupt flag to avoid unintended recursive interrupts
BTFSS PORTB,0 ; Check if the higher priority input is 1
GOTO DONE ; Higher priority input is not 1 so we ignore this change
BCF INTCON,RBIF ; Better clear this flag as soon as you start to service it
CALL TEMPERATURA ; Calling as a subroutine is supported up to 8 levels by this micro
DONE
; BSF INTCON,GIE ; Don't do it, because the RETFIE instruction does it for you
RETFIE
; If the program reaches here, the high priority input is 1.
; Now we need to check if the low priority input is 1 as well.
TEMPERATURA
BTFSC PORTB,7
BSF PORTB,3
; BSF INTCON,GIE ; Not needed since we return to the ISR routine and RETFIE will do it for us
RETURN
And finally let's simplify the above ode by eliminating unnecessary code lines:
INTERRUPCIONES
BTFSS INTCON,INTF
GOTO DONE ; Not INTF interrupt simply skip
BCF INTCON,INTF ; Better clear this flag as soon as you start to service it
BSF PORTB,0 ; High priority input goes 1 hence no more questions to setting the output as 1
; Check for PORTB on change interrupt
BTFSS INTCON,RBIF
GOTO DONE ; Not RBIF interrupt simply skip
BCF INTCON,RBIF ; First of all clear the interrupt flag to avoid unintended recursive interrupts
BTFSS PORTB,0 ; Check if the higher priority input is 1
GOTO DONE ; Higher priority input is not 1 so we ignore this change
BCF INTCON,RBIF ; Better clear this flag as soon as you start to service it
CALL TEMPERATURA ; Calling as a subroutine is supported up to 8 levels by this micro
DONE
RETFIE
; If the program reaches here, the high priority input is 1.
; Now we need to check if the low priority input is 1 as well.
TEMPERATURA
BTFSC PORTB,7
BSF PORTB,3
RETURN

Understanding AVR code for disabling and restoring SREG interrupt state

I'm somewhat confused by the examples of how to disable and restore the interrupt state that I've found for 8-bit AVR processors.
8-bit AVR processors like the ATmega 2560 have a Global Interrupt Enable bit (labelled 'I') in the Status Register (SREG). The CLI instruction disables all interrupts by clearing that bit. From the AVR Instruction Set Manual:
CLI - Clear Global Interrupt Enable Bit
Description
Clears the Global Interrupt Enable (I) bit in SREG (Status Register). The interrupts will be immediately disabled. No interrupt will be executed after the CLI instruction, even if it occurs simultaneously with the CLI instruction. (Equivalent to instruction BCLR 7.)
The AVR Instruction Set Manual also shows the following example:
1 in temp, SREG ; Store SREG value (temp must be defined by user)
2 cli ; Disable interrupts during timed sequence
3 sbi EECR, EEMWE ; Start EEPROM write
4 sbi EECR, EEWE
5 out SREG, temp ; Restore SREG value (I-flag)
The intent of line 5 seems to be to restore SREG's I-flag to the value that it had just before line 2 was executed. In fact, this code stores the state of all of SREG's flags - it just seems to assume that the values of SREG's other flags won't change between lines 1 and 5. However, if an interrupt occurred between lines 1 and 2, couldn't it cause some of SREG's other flags to be "restored" incorrect?
1 in temp, SREG ; Store SREG value (temp must be defined by user)
; <------- interrupt occurs here
2 cli ; Disable interrupts during timed sequence
3 sbi EECR, EEMWE ; Start EEPROM write
4 sbi EECR, EEWE
5 out SREG, temp ; Restore SREG value (I-flag)
When interrupt happen the CPU will switch to interrupt service routine but before switching the CPU will remember the location of the program (by push Program counter in the stack)
CPU will execute ISR
after execute ISR It's very important and crucial to restore CPU environment (SERG, GPR, SP, PC) as before interrupt this will be done by your code(if you did not restore CPU environment after interrupt your program will crush With High probability)
CPU will Return to the same location (by restore PC from Stack)
1 in temp, SREG ; Store SREG value (temp must be defined by user)
; <------- interrupt occurs here
; <-------------go to interupt handler
; <--------Rutern from interupt with same value of temp, SREG, and all GPR are same value
2 cli ; Disable interrupts during timed sequence
3 sbi EECR, EEMWE ; Start EEPROM write
4 sbi EECR, EEWE
5 out SREG, temp ; Restore SREG value (I-flag)
the above code simply telling you "Make sure that the line 3,4 will execute after each other with no interrupt"
if an interrupt occurred between lines 1 and 2, couldn't it cause some of SREG's other flags to be "restored" incorrect?
if an interrupt occurred between lines 1 and 2,the interrupt will be handled and return before the line 2 and Any interrupt code Must preserve CPU Environment

How to erase msp430f2619 flash using bsl?

I want to do mass erase on my msp430f2619 using bsl. I use software jump in my code to invoke bsl. I send 0x80, get 0x90 from BSL(ack). Then i send mass erase command and get 0x90 again. Then i power off my device, then i power on the device, then i send 0x80 and get 0x90, that means there was no mass erase operation.
Read command is not working too. I send password (0xFF 32 times), after that send rx command, then i get few coorect bytes, and then infinite raw of 0xff.
I think i miised something before jump to bsl, please give an example code, or step by step instruction on how to make software jump to bsl and make it work correctly.
If you are sending 0x80 only, then get back 0x90, this confirms you have entered into the BSL since this completes the required synchronization sequence (see section 2.1 of this document). You should not require the "RX password" command since the "Mass erase" command is not protected.
The next sequence after the synchronization is to send the desired command, which should be the "Mass erase". There is a format to each of the BSL commands called the data frame. You want to send the following data frame: eight mandatory bytes (note two dummy bytes), and two checksum bytes. Note the "Mass erase" command does not contain data bytes, but you need to calculate the checksum bytes. Here are the bytes to be sent to perform the mass erase:
80 18 04 04 dd dd 06 A5 CL CH
Where: dd = dummy bytes (any value accepted), CL = Checksum low, CH = Checksum high
After sending this data frame then you should receive the ACK (0x90) byte. Then power off the device.

Declaring 16bit memory variable in assembly

I'm starting to study assembly for PIC18f4550 and I've been trying to do some activities and I don't know how to solve it. According to the activity, Using MPLABX, I'm supposed to sum 2 16bit variables and store the result on a third 16 bit variable.
I was able to sum and store the result on the third variable but I have no idea how to declare these variables in 16bit.
; TODO INSERT CONFIG CODE HERE USING CONFIG BITS GENERATOR
INCLUDE
RES_VECT CODE 0x0000 ; processor reset vector GOTO START ; go to beginning of program
; TODO ADD INTERRUPTS HERE IF USED
MAIN_PROG CODE ; let linker place main program
START
clrw ;clear the w register
num1 equ 00000 ;declares 3 variables and their initial values
num2 equ 00001
result equ 00002
movlw H'4F'
movwf num1
movlw H'8A'
movwf num2
movf num1,W ;moves num1 value to w register
addwf num2,W ;sums num2 and w and stores it in w itself
movwf resultado ;moves w to the result register
END
I need to check if my code is actually correct (Im totally new on assembly) and how to declare these 3 variables in 16bit format. Thanks in advance!
The PIC18 is a 8 bit controller. If you want to add two 16 bit variables you had to do it byte by byte.
Maybe you don't want to work with an absolue address and work with the linker:
udata_acs H'000'
num1_LSB RES 1 ;reserve one byte on the access bank
num1_MSB RES 1 ;
You also could reserve two bytes for a name:
udata_acs H'000'
num1 RES 2 ;reserve two bytes on the access bank
Know you could access the second byte with :
movwf num1+1
And always remember to check the carry bit to get the MSB of an addition.