• AVR Freaks

Hot!IOC Issue using PIC 16LF18346 NOT RESOLVED

Author
cogeniac
Starting Member
  • Total Posts : 32
  • Reward points : 0
  • Joined: 2017/02/04 19:50:39
  • Location: 0
  • Status: offline
2021/01/08 12:37:26 (permalink)
0

IOC Issue using PIC 16LF18346 NOT RESOLVED

I have been working through debugging a program to read encoder inputs using Interrupt on Change (IOC) on a PIC 16LF18346. 
I am currently testing it on only two pins RC0 and RC1, but eventually there will be four encoders using all 7 of the RCx bits. I have these set up as digital inputs, and the pull-ups are on. 
I have enabled the IOC module (PMD0, bit 0 cleared), set the IOCCP bits (in this case to 0x03, to enable rising edge IOC on RC0 and RC1), set the IOCIE bit (PIE0, bit 4), and set INTCON to 0xC1 (GIE, PEIE, and INTEDG set). So, everything SHOULD be ready for an IOC event. 
 
I can turn the encoder and watch the pins on PORTC change appropriately in the MPLAB X debugger, however, I get no interrupt when these bits change. 
 
Am I missing something? 
 
Note: This device uses the MCHP Curiosity Board as the debug header. This board has some weird peripheral stuff that is not documented. For a while I could not get RC0 to respond properly. After reviewing the Curiosity Board schematic, I found that RC0 is connected through a small resistor network to a voltage divider. This includes potentiometer connected to VDD. Turning the pot caused the signal to either not reach Vdd, or not reach ground. So, even though the pin was being driven between 0v and 3.3v, the resistor network made it go between 3.3v (1) and 2.5 v (0) with the pot set one way, or between 0v (0) and 1v (1). My solution tooth's was to remove R33 from the back side of the board, thereby eliminating the network entirely. So, beware!
post edited by cogeniac - 2021/01/13 10:01:35
#1

9 Replies Related Threads

    cogeniac
    Starting Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2017/02/04 19:50:39
    • Location: 0
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/08 17:45:42 (permalink)
    0
    I think I solved this. I have read in several places that to clear the interrupt flags properly, you need to do a port read, clear the interrupt and then read the port again. 
     
    I was doing this in the ISR, but NOT when I first set up the interrupts.
     
    So now, after I set up the interrupt enable registers, I do the following steps before entering the main loop. 
    movf PORTC  ;read PORTC
    clrf IOCAF     ;Clear the PORT A Interrupt flags
    clrf IOCBF     ;Clear the PORT B Interrupt flags
    clrf IOCCF     ;Clear the PORT C Interrupt flags
    movf PORTC  ;Read PORT C again
     
    Then in the ISR I do the following before going to RETFIE
     
    movlb 0x00 
    movf PORTC,w    ;Read PORTC
    movlb 0x07
    clrf IOCCF          ;Clear the PORTC interrupt flags
    movf PORTC,w    ;Read PORTC again
     
    And doing this the interrupts finally appear to be working.
    #2
    1and0
    Access is Denied
    • Total Posts : 11747
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/08 22:31:15 (permalink)
    0
    cogeniac
    I think I solved this. I have read in several places that to clear the interrupt flags properly, you need to do a port read, clear the interrupt and then read the port again. 

    Where did you read this? On older PIC16 devices, the port is read to end the mismatch condition before the interrupt flag can be cleared, but your PIC16 is a newer enhanced device. Also, I don't think the port needed to be read again afterward.
     
    cogeniac
    I was doing this in the ISR, but NOT when I first set up the interrupts.
     
    So now, after I set up the interrupt enable registers, I do the following steps before entering the main loop. 
    movf PORTC  ;read PORTC
    clrf IOCAF     ;Clear the PORT A Interrupt flags
    clrf IOCBF     ;Clear the PORT B Interrupt flags
    clrf IOCCF     ;Clear the PORT C Interrupt flags
    movf PORTC  ;Read PORT C again

    That is NOT going to work because PORTx and ICOxF are located in different banks.
     
    cogeniac
    Then in the ISR I do the following before going to RETFIE
     
    movlb 0x00 
    movf PORTC,w    ;Read PORTC
    movlb 0x07
    clrf IOCCF          ;Clear the PORTC interrupt flags
    movf PORTC,w    ;Read PORTC again
     
    And doing this the interrupts finally appear to be working.

    Again, different banks. Search and read your PIC datasheet because there's a section on how to clear IOC interrupt flags.
    #3
    ric
    Super Member
    • Total Posts : 29434
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: IOC Issue using PIC 16LF18346 2021/01/08 23:02:36 (permalink)
    +1 (1)
    Can we see your not working code?
    As 1and0 mentioned, the snippet of initialisation code you posted lacks any bank selecting instructions.
    These newer IOC implementations do NOT require a port read. The "previous" status is updated when you write to the IOCAFx flag, as shown in "FIGURE 15-1: INTERRUPT-ON-CHANGE BLOCK DIAGRAM" in the datasheet.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #4
    cogeniac
    Starting Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2017/02/04 19:50:39
    • Location: 0
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/08 23:35:21 (permalink)
    0
    In the original code (I no longer have an example of it, since I changed it). I did not clear the IOCCF flag and I did not do the initial and post PORTC reads. I just set the various interrupt enable bits and went from there. The IOC did not respond. 
     
    Once I put the PORTC read and IOCCF clear steps in the initialization sub, the IOC started working. 
     
    I'll walk through this in the AM and try to back up to where I was, but I tried taking out the PORTC reads and the IOC didn't work. 
    #5
    ric
    Super Member
    • Total Posts : 29434
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: IOC Issue using PIC 16LF18346 2021/01/09 01:31:13 (permalink)
    -1 (1)
    More likely you missed a bank select.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #6
    cogeniac
    Starting Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2017/02/04 19:50:39
    • Location: 0
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/09 07:44:40 (permalink)
    0
    OK. I did some experiments, and I am more confused.  Here is the main program and the setup subroutine. I have bolded the code that involves IOC. There are other segments of code that have been commented out where I was trying various things to get the the IOC to work.
    This morning I tried commenting out all of the code that I had added to try to get IOC to work (down in the setup routine). After realizing that I needed to enable both positive edge and negative edge IOC to get all of the encoder states, it seems to work as is. Strangely, however, for the last 2-3 days it did not throw any interrupts with the code as it is here. It was only after I cleared the IOCCF flags and read PORTC that it started to work. 
     
    The negative edge detection is required since the encoder sequence is 0x00, 0x01, 0x03, 0x02, 0x00, so the last two transitions were being missed. But I had turned the knob multiple times and gotten no interrupts.. so I'm not sure what was going on. It works now though.
     
    ;******************************************************************************
    ; main program
    ; Loops through a cyle that disables interrupts, reads PORT A,
    ; enables the interrupts, and waits about 10 msec for a knob turn or an I2C
    ; write. If either of these occurs, it then services the approriate
    ; interrupt.
    ;******************************************************************************
    PSECT main,class=CODE,delta=2
    main:
    movlb 0x00      ;Switch to Bank 0
    bcf INTCON,7    ;Disable all interrupts during setup - bit 7=GIE
    bcf INTCON,6    ;Disable all interrupts during setup
    PAGESEL setup
    call setup
    PAGESEL $
    MainLoop:          ;*******************This loop continues until there is an interrupt
    bsf INTCON,7       ;Enable all interrupts
    bsf INTCON,6       ;Enable all peripheral interrupts
    movf intCounter,w  ;Put intCounter value in w - set up to determine if intCounter has any set bits
    addlw 0xff         ;add 0xFF to w
    btfss STATUS,0     ;If any bits were set there will have been a carry in the above add
    goto MainLoop      ;If not, then go to the start
    ;*************** This section determines what interrupt occurred based on what was set by the ISR
    ;THIS SECTION IS HERE TO CAPTURE MULTIPLE INTERRUPTS AND THE SYSTEM STATE AT EACH> I AM CURRENTLY NOT USING IT
    ; PAGESEL getState

    ; call getState ;If so, then get the data for the oldest interrupt (top of the arrays)
    ; PAGESEL $
    movlb 0x00         ;Switch to Bank 0 (in case we were not there already)
    PAGESEL SSP1Handler
    btfsc intFlag,0    ;If intFlag Bit 0 is clear then interrupt was not SSP1
    call SSP1Handler   ;If intFlag Bit 0 is set then interrupt was SSP1 I2C
    PAGESEL SSP2Handler
    btfsc intFlag,1    ;If intFlag Bit 1 is clear then interrupt was not SSP2
    call SSP2Handler   ;If intFlag Bit 1 is set then interrupt was SSP2 I2C (RPI Command)
    btfsc intFlag,2    ;If intFlag Bit 2 is clear then interrupt was not a knob turn?
    call KnobHandler   ;If Knob, then go handle the knob change
    movf intCounter,w  ;Put intCounter value in w - set up to determine if intCounter has any set bits
    sublw 00000000B    ;subtract w from zero
    btfss STATUS,0     ;If the interrupt counter is zero (no borrow), skip and go the start
    decf intCounter    ;Otherwise decrement the interrupt counter and go to the start
    goto MainLoop
    ;******************************************************************************
    ;  NOTE THE PIN ASSIGNMENTS IN THIS DESCRIPTION ARE DIFFEREN THAN WHAT IS ON THE BOARD> THIS IS FOR THE NEXT BOARD ITERATION> CURRENTLY WE ARE ONLY LOOKING AT ENCODER INPUTS ON RC0 and RC1
    ; Setup Code to initialize program variables and peripheral registers
    ; and setup the MSSP for I2C
    ; Ports:
    ; Bidirectional Ports:
    ; RB4=I2C-SDA1 RB5=I2C-SCL1,
    ; RB6=I2C-SDA2,RB7=I2C-SCL2
    ; Input Ports:
    ; RC0=I-Vol, RC1=Q-Vol (encoder inputs)
    ; RC2=I-Src, RC3=Q-Src (encoder inputs)
    ; RC4=I-Bal, RC5=Q-Bal (encoder inputs)
    ; RC6=I-EQ, RC7=Q-EQ (encoder inputs)
    ;
    ; Output Ports:
    ; RA2=fSetA RA3=fSetB (Audio Clock Control Buts)
    ; RA4=GPIO request I2C read by RPI
    ; RA5=DAC Mute (XSMT)
    ;
    ; Unused Ports:
    ; RA3: to avoid MCLR issue with debugger
    ;******************************************************************************
    setup:
    ;******************************************************************************
    ; Disable Peripheral modules
    ;******************************************************************************
    ; movlb 0x12
    ; movlw 0xFF
    ; movwf PMD1 ;Disable timer modules
    ; movwf PMD2 ;Disable DAC and Comparator modules
    ; movwf PMD3 ;Disable PWM modules
    ; movwf PMD5 ;Disable Signal modulator module
    ; movlw 00100000B
    ; movwf PMD4 ;Enable MSSP1 and MSSP2, Disable UART
    ; movlw 01000110B
    ; movwf PMD0 ;Enable IOC Module, disable FVR, NVM and clock reference
    ;******************************************************************************
    ;Disable the analog inputs
    ;******************************************************************************
    ; movlb 0x00
    movlw 0xFF
    ; movwf PORTC
    ; clrf PORTA
    ; clrf PORTB
    ; clrf PORTC
    ; movlb 0x02
    ; clrf LATA
    ; clrf LATB
    ; clrf LATC
    movlb 0x03          ;select Bank 3
    clrf ANSELA         ;clear the analog input bits
    clrf ANSELB         ;clear the analog input bits
    clrf ANSELC         ;clear the analog input bits
    ;******************************************************************************
    ; Set the tri-state registers to configure I/O pins
    ;******************************************************************************
    movlb 0x01          ;select Bank 1
    movlw 0x3F
    movwf TRISA         ;Set Port A TRIS bits to all input
    movlw 0x03
    movwf TRISC         ;Set PortC pins 0 and 1 as input, 2-7 as output
    ;******************************************************************************
    ; Configure the bidirectional pins for the SSP (I2C) RB4-RB7
    ;******************************************************************************
    ;
    movlb 0x0D          ;select bank 13
    movlw 00011001B
    movwf RB4PPS        ;Set RB4 as SDA1 input
    movlw 00011011B
    movwf RB5PPS        ;Set RB5 as SDA2 input
    movlw 00011000B
    movwf RB6PPS        ;Set RB6 as SCL1 input
    movlw 00011010B
    movwf RB7PPS        ;Set RB7 as SCL2 input
    movlw 00001110B
    movwf SSP1CLKPPS    ;Set SSP1 SCL input to RB6
    movlw 00001100B
    movwf SSP1DATPPS    ;Set SSP1 SDA input to RB4
    movlw 00001111B
    movwf SSP2CLKPPS    ;Set SSP2 SCL input to RB7
    movlw 00001101B
    movwf SSP2DATPPS    ;Set SSP2 SCL input to RB5
    ;******************************************************************************
    movlb 0x04          ;select Bank 4
    movlw 0xFF
    movwf WPUA          ;enable weak pullups on port A
    movwf WPUB          ;enable weak pullups on port B
    movlw 0x03
    movwf WPUC          ;enable weak pullups on port C RC0 and RC1
    ; clrf SSP1STAT     ;Clear SSP 1 status register
    ;*******************************
    movlb 0x01          ; Switch to Bank 1
    clrf PIE0           ;Disable all peripheral interrupts
    clrf PIE1 
    clrf PIE2
    bsf PIE0,4          ;Enable IOC interrupts
    ; bsf PIE1,3        ;Enable SSP1 interripts
    ; bsf PIE2,3        ;Enable SSP2 interripts
    ;*******************************
    movlb 0x07          ;select Bank 7
    movlw 00111111B
    movwf IOCAP         ;Enable positive IOC on PORTA RA0-RA5
    movwf IOCAN                ;Enable negative IOC on PORTC RAO-RA5
    movlw 00000011B
    movwf IOCCP         ;Enable positive IOC on PORTC, RC0 & RC1
    movwf IOCCN                ;Enable negative IOC on PORTC, RC0 & RC1
    ;*******************************
    movlb 0x00 ;Select bank 0
    ; clrf FSR0L
    clrf PIR0           ;Clear the interrupt flags
    clrf PIR1
    clrf PIR2
    clrf PIR3
    clrf PIR4
    ; movf PORTC    THIS WAS IN THE CODE THAT WORKED, BUT I AM NOT SURE IT IS NECESSARY
    ;movlb 0x07
    ;clrf IOCAF          
    ;clrf IOCBF
    ;clrf IOCCF
    ; movf PORTC
    clrf intCounter ;clear the interrupt counter
    clrf intFlag ;Clear the Interrupt Flag
    clrf knbTemp2
    clrf newKnobState
    clrf knobState
    clrf knobFlag
    clrf intFlag
    clrf FSRsave
    clrf STATUSsave
    clrf WREGsave
    return
     
    #7
    cogeniac
    Starting Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2017/02/04 19:50:39
    • Location: 0
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/13 10:45:27 (permalink)
    0
    OK, so I had the IOC working reliably, but the program was not detecting the correct encoder. After some mucking around, I realized that I was not initializing the variable with the encoder states at the start (I was just clearing it, but not reading the ports and setting it up properly). 
     
    So I added a PORTA and PORTC read just before entering the main loop. This should have simply put the state of the encoders into the variable (Note there is some messiness to this, since with my current encoder test board, the encoders are not all on the same port, so I have to mess with the bit positions a bit. That will change in the next iteration). 
    After doing this, the IOC function again refused to cooperate...It worked fine until I added these port reads, and now it doesn't work with or without them!
     
    There is obviously still something I do not understand about properly activating the IOC function.
     
    Here is the currently non-working code, including the ISR and the setup routines. Again the IOC initialization sections are bold. 
     

    ;******************************************************************************
    ;
    ; ISR Interrupt Service Routine: responds to I2C notifications and
    ; encoder input knob interrupts
    ;
    ;****************************************************************************** ;
    ISR:
       movlb 0x00
       bcf INTCON,7          ;Disable all interrupts
       bcf INTCON,6          ;Disable all peripheral interrupts
       incf intCounter       ;increment the interrupt counter
       clrf intFlag          ;Clear the interrupt flag so we can set it later for this interrupt
       btfss PIR1,3          ;Is this a SSP1 interrupt?
       goto SSP2Interrupt    ;No, go see if it was an I2C slave read
       bcf PIR1,3            ;Yes, Clear the SSP1 interrupt flag
       bsf intFlag,0         ;Set intFlag bit 0 so we know that the interrupt was SSP1
       goto ISRDone      
    SSP2Interrupt:
       btfss PIR2,3          ;Is this a SSP2 interrupt?
       goto KnbTurn          ;No, go figure out which knob turned
       bcf PIR2,3            ;Yes, Clear the SSP2 interrupt flag
       bsf intFlag,1         ;Set intFlag bit 1 so we know that the interrupt was SSP2
       goto ISRDone
    KnbTurn:
       bcf PIR0,0            ;clear the IOC peripheral interrupt flag
       movf PORTA,w          ;read the PORTA pins (also clears the port for next interrupt)
       movlb 0x07            ;select bank 7
       clrf IOCAF            ;clear the Port A interrupt flags
       movlb 0x00            ;select bank 0
       movwf newKnobState    ;save the current encoder states
       movlw 0x3F            ;mask off only lower 6 bits -the IQ bits on RA0-RA5
       andwf newKnobState,1
       movf PORTC,w          ;read the PORTC pins (also clears the port for next interrupt)
       movlb 0x07            ;select bank 7
       clrf IOCCF            ;clear the Port C interrupt flag
       movlb 0x00            ;select bank 0
       movwf knbTemp2        ;save the PORTC state
       movlw 0000011B        ;mask to capture I-Q bits of PORTC (bits 0 & 1)
       andwf knbTemp2,1      ;Capture bits 0 and 1 of PORTC
    ; This set of shifts is necessary because we are currently using RC0 and RC1 for the EQ inputs
    ; so we need to move them intot he right bit positions to create newKnobState
       rlf knbTemp2,1        ;Rotate original bits 0 and 1 into bit positons 1 and 2
       rlf knbTemp2,1        ;Rotate original bits 0 and 1 into bit positions 2 and 3
       rlf knbTemp2,1        ;Rotate original bits 0 and 1 into bit positions 3 and 4
       rlf knbTemp2,1        ;Rotate original bits 0 and 1 into bit positions 4 and 5
       rlf knbTemp2,1        ;Rotate original bits 0 and 1 into bit positions 5 and 6
       rlf knbTemp2,1        ;Rotate original bits 0 and 1 into bit positions 6 and 7
    ;XOR the old and new knob states to determine what changed
       movf knbTemp2,w
       iorwf newKnobState,w  ;add the PORTC bits (originally 0 & 1, now 6 and 7) into newKnobState to  
                              make a full 8-bit word
       xorwf knobState,w     ;XOR old and new knob states (will set one of the bits corresponding to
                             the knob that changed)
       movwf knobFlag        ;set the knob flag (will have one of the bits corresponding to the turned
                             knob set)
       bsf intFlag,2         ;set the interrupt flag to a knob turn
    ISRDone:
       RETFIE                ;Return from interrupt
    ;******************************************************************************
    ; main program
    ; Loops through a cyle that disables interrupts, reads PORT A,
    ; enables the interrupts, and waits about 10 msec for a knob turn or an I2C
    ; write. If either of these occurs, it then services the approriate
    ; interrupt.
    ;******************************************************************************
    PSECT main,class=CODE,delta=2
    main:
       movlb 0x00 ;Switch to Bank 0
       bcf INTCON,7         ;Disable all interrupts during setup - bit 7=GIE
       bcf INTCON,6         ;Disable all interrupts during setup
       PAGESEL setup
       call setup
       PAGESEL $
    ;Capture the initial encoder state  THIS IS THE NEW CODE> THE IOC NOW DOESN"T WORK WITH OR WITHOUT THIS CODE
    ;  movf PORTA,w         ;read the PORTA pins
    ;  movwf knobState      ;save the current encoder states
    ;  movlw 0x3F           ;mask off only lower 6 bits -the IQ bits
    ;  andwf knobState,1
    ;  movf PORTC,w         ;read the PORTC pins
    ;  movwf knbTemp2       ;save the PORTC state
    ;  movlw 0000011B       ;mask to capture I-Q bits of PORTC (bits 0 & 1)
    ;  andwf knbTemp2,1     ;Capture bits 0 and 1 of PORTC
    ;  rlf knbTemp2,1       ;Rotate original bits 0 and 1 into bit positons 1 and 2
    ;  rlf knbTemp2,1       ;Rotate original bits 0 and 1 into bit positions 2 and 3
    ;  rlf knbTemp2,1       ;Rotate original bits 0 and 1 into bit positions 3 and 4
    ;  rlf knbTemp2,1       ;Rotate original bits 0 and 1 into bit positions 4 and 5
    ;  rlf knbTemp2,1       ;Rotate original bits 0 and 1 into bit positions 5 and 6
    ;  rlf knbTemp2,1       ;Rotate original bits 0 and 1 into bit positions 6 and 7
    ;  movf knbTemp2
    ;  iorwf knobState,1    ;add the PORTC bits (originally 0 & 1, now 6 and 7) into newKnobState to
                            make a full 8-bit word

    MainLoop: ;*******************This loop continues until there is an interrupt
       bsf INTCON,7         ;Enable all interrupts
       bsf INTCON,6         ;Enable all peripheral interrupts
       movf intCounter,w    ;set up to determine if intCounter has any set bits
       addlw 0xff           ;add 0xFF to w
       btfss STATUS,0       ;If any bits were set there will have been a carry in the above add
       goto MainLoop        ;If not, then go to the start
    ;*********This section determines what interrupt occurred based on how intFlag was set by the ISR
       movlb 0x00           ;Switch to Bank 0 (in case we were not there already)
       PAGESEL SSP1Handler
       btfsc intFlag,0      ;If intFlag Bit 0 is clear then interrupt was not SSP1
       call SSP1Handler     ;If intFlag Bit 0 is set then interrupt was SSP1 I2C
       PAGESEL SSP2Handler
       btfsc intFlag,1      ;If intFlag Bit 1 is clear then interrupt was not SSP2
       call SSP2Handler     ;If intFlag Bit 1 is set then interrupt was SSP2 I2C (RPI Command)
       btfsc intFlag,2      ;If intFlag Bit 2 is clear then interrupt was not a knob turn?
       PAGESEL KnobHandler
      call KnobHandler      ;If Knob, then go handle the knob change
       movf intCounter,w    ;set up to determine if intCounter has any setbits
       sublw 00000000B      ;subtract w from zero
       btfss STATUS,0       ;If the interrupt counter is zero (no borrow), skip and go the start
       decf intCounter      ;Otherwise decrement the interrupt counter and go to the start
       goto MainLoop
    ;******************************************************************************
    ;
    ; Setup Code to initialize program variables and peripheral registers
    ; and setup the MSSP for I2C
    ; Ports:
    ; Bidirectional Ports:
    ; RB4=I2C-SDA1 RB5=I2C-SCL1,
    ; RB6=I2C-SDA2,RB7=I2C-SCL2
    ; Output Ports:
    ; RA2=fSetA RA3=fSetB (Audio Clock Control Buts)
    ; RA4=GPIO request I2C read by RPI
    ; RA5=DAC Mute (XSMT)
    ;
    ; Unused Ports:
    ; RA3: to avoid MCLR issue with debugger
    ;Input Ports:
    ; RA2=I-Vol, RA1=Q-Vol (encoder inputs)
    ; RA0=I-Src, RA3=Q-Src (encoder inputs)
    ; RA4=I-Bal, RA5=Q-Bal (encoder inputs)
    ; RC0=I-EQ, RC1=Q-EQ (encoder inputs)
    ;******************************************************************************
    setup:

    movlb 0x03              ;select Bank 3
    clrf ANSELA             ;clear the analog input bits
    clrf ANSELB             ;clear the analog input bits
    clrf ANSELC             ;clear the analog input bits
    ;******************************************************************************
    ; Set the tri-state registers to configure I/O pins
    ;******************************************************************************
    movlb 0x01              ;select Bank 1
    movlw 0x3F
    movwf TRISA             ;Set Port A TRIS bits to all input
    movlw 0x03
    movwf TRISC             ;Set PortC pins 0 and 1 as input, 2-7 as output
    ;******************************************************************************
    ; Configure the bidirectional pins for the SSP (I2C) RB4-RB7
    ;******************************************************************************
    ;
    movlb 0x0D              ;select bank 13
    movlw 00011001B
    movwf RB4PPS            ;Set RB4 as SDA1 input
    movlw 00011011B
    movwf RB5PPS            ;Set RB5 as SDA2 input
    movlw 00011000B
    movwf RB6PPS            ;Set RB6 as SCL1 input
    movlw 00011010B
    movwf RB7PPS            ;Set RB7 as SCL2 input
    movlw 00001110B
    movwf SSP1CLKPPS        ;Set SSP1 SCL input to RB6
    movlw 00001100B
    movwf SSP1DATPPS        ;Set SSP1 SDA input to RB4
    movlw 00001111B
    movwf SSP2CLKPPS        ;Set SSP2 SCL input to RB7
    movlw 00001101B
    movwf SSP2DATPPS        ;Set SSP2 SCL input to RB5
    ;******************************************************************************
    movlb 0x04              ;select Bank 4
    movlw 0xFF
    movwf WPUA              ;enable weak pullups on port A
    movwf WPUB              ;enable weak pullups on port B
    movlw 0x03
    movwf WPUC              ;enable weak pullups on port C RC0 and RC1
    ; clrf SSP1STAT         ;clear SSP 1 status register
    ; clrf SSP2STAT         ;clear SSP 1 status register
    ;******************************************************************************
    movlb 0x01             ;Switch to Bank 1
    clrf PIE0              ;Disable all peripheral interrupts
    clrf PIE1 
    clrf PIE2
    bsf PIE0,4             ;Enable IOC interrupts
    ; bsf PIE1,3           ;Enable SSP1 interripts
    ; bsf PIE2,3           ;Enable SSP2 interripts
    ;******************************************************************************
    movlb 0x07             ;select Bank 7
    movlw 00111111B
    movwf IOCAP            ;Enable positive IOC on PORTA RA0-RA5
    movwf IOCAN            ;Enable negative IOC on PORTA RA0-RA5
    movlw 00000011B
    movwf IOCCP            ;Enable positive IOC on PORTC, RC0 & RC1
    movwf IOCCN            ;Enable negative IOC on PORTA RC0 & RC1
    ;******************************************************************************
    movlb 0x00             ;Select bank 0
    clrf PIR0              ;Clear the interrupt flags
    clrf PIR1
    clrf PIR2
    clrf PIR3
    clrf PIR4
    ; movlb 0x07           ;I HAVE TRIED THIS WITH AND WITHOUT THE CLEARING OF THE IOCxF REGISTERS
    ; clrf IOCAF
    ; clrf IOCBF
    ; clrf IOCCF

    ;******************************************************************************
    movlb 0x00
    clrf intCounter         ;clear the interrupt counter
    clrf intFlag            ;Clear the interrupt type flag
    clrf newKnobState
    clrf knobFlag
    return
    ;
    ;******************************************************************************
    ; KnobHandler subroutine to determine which knob was turned,
    ; and in which direction,and implement the corresponding change
    ;******************************************************************************
    ;
    KnobHandler:
       nop                  ;Figure out which knob turned
       movlb 0x00           ;select Bank 0
       btfsc knobFlag,0     ;test bit 0, if set, then turn was volume knob
       goto VolKnob         ;go handle volume knob
       btfsc knobFlag,1     ;if bit 0 clear, test bit 1,
                            ;if bit 1 set, then turn was volume knob
       goto VolKnob         ;go handle volume knob
                            ;otherwise go test src knob
       btfsc knobFlag,2     ;test bit 2, if set, then turn was Source knob
       goto SrcKnob
       btfsc knobFlag,3     ;if bit 2 clear, test bit 3,
                            ;if bit 3 set, then turn was Source knob
       goto SrcKnob         ;go handle source knob
       btfsc knobFlag,4     ;if bit 3 clear, test bit 4,
                            ;if bit 4 set, then turn was Balance knob
       goto BalKnob         ;go handle balance knob
       btfsc knobFlag,5     ;if bit 4 clear, test bit 5,
                            ;if bit 5 set, then turn was balance knob
       goto BalKnob         ;go handle balance knob
       btfsc knobFlag,6     ;if bit 5 clear, test bit 6,
                            ;if bit 6 set, then turn was EQ knob
       goto EQKnob          ;go handle balance knob
       btfsc knobFlag,7     ;if bit 6 clear, test bit 7,
                            ;if bit 7 set, then turn was EQ knob
       goto EQKnob          ;go handle EQ knob
       return               ;otherwise return, (error)
    SrcKnob:
       nop                  ;Determine CW or CCW Direction for Source Knob
       movlw 0x0C           ;Mask for source knob bits
       andwf knobState,1    ;mask off only src bits in prior knob state
       andwf newKnobState,0 ;mask off only src bits in current knob state
       movwf knbTemp        ;save the new state in temp variable
       btfsc knbTemp,3      ;If bit 3 is clear, then skip
       bsf knbTemp,1        ;If bit 3 is set, then set bit 1, to prepare for circular left shift
       rlf knbTemp,1        ;shift new state (newKnobState) bits left (if Bit 1 was set then it  
                            rotates [font="'courier new', courier"]in to bit 2 as Bit 3)
       movf knbTemp,w
       xorwf knobState,0    ;xor the new -in W- and prior knob state values
       movwf knbTemp
       btfsc knbTemp,3      ;if bit 3 is set, then turn was clockwise, so skip and increment source
       goto SrcDec          ;otherwise turn was CCW, go decrement source
    ;THE REST OF THIS JUST REACTS TO VARIOUS KNOB TURNS
    ;*******************************************************************************

    ;
    ; Source is defined by srcCount variable as follows:
    ;
    ; totSrc=0x05
    ; srcCount=0x00 Analog Input srcReg 2D 0x00 rxReg 0D 0x00
    ; srcCount=0x01 RPI Input srcReg 2D 0x01 rxReg 0D 0x00
    ; srcCount=0x02 TOS-1 srcReg 2D 0x02 rxReg 0D 0x00
    ; srcCount=0x03 TOS-2 srcReg 2D 0x02 rxReg 0D 0x01
    ; srcCount=0x04 S/PDIF-1 srcReg 2D 0x02 rxReg 0D 0x02
    ; srcCount=0x05 S/PDIF-2 srcReg 2D 0x02 rxReg 0D 0x03
    ;
    ; Note: Analog input (from the ADC) goes to input Port A on the ASRC (via I2S)
    ; RPI input goes to inout Port B on the ASRC (via I2S)
    ; The other PCM inputs are via the ASRC DIR.
    ; So selection of these different sources are handled by
    ; different functions and registers inthe ASRC.
    ;
    SrcInc: movf srcCount,w ;check to see if source is at max
    subwf totSrc,0
    movf srcRoll1,w ;load rollover value (0xFF minus Source Total)
    btfss STATUS,2
    addwf srcCount,1 ;if so, then rollover to 0xFF
    incf srcCount,1 ;increment the source counter - goes to zero
    ;if srcRoll1 was added, otherwise just increments
    goto setSrc ;jump to the source set code
    SrcDec: movlw 0x00
    subwf srcCount,0 ;check to see if source is at min
    movf srcRoll2,w
    btfss STATUS,2
    addwf srcCount,1 ;if so, then rollover to srcTot+1, srcRoll2
    decf srcCount,1 ;decrement the source counter - either decrements
    ;within range, or rolls under from 0 to srcTot
    setSrc: RETURN
    ; movf srcCount,w ;preset the srcCount to add later if necesary
    ; clrf srcCtlReg ;preset SRC control reg (2D) input to ASRC Port A "00000000"
    ; movlw 0x0D ;Add 0x0D to scrCount, to see if the value is 3 or more
    ; addlw srcCount ;if value is over 2, then carry bit will be set
    ; btfss STATUS,0 ;check to see if carry is set (srcCount>2) ;
    ; goto DIRSet ;if so, go set up the DIR
    ; addwf srcCtlReg ;if not, then add the value of srcCount to srcCtlReg
    ;to set it to '00000000" (ASRC Port A) or "00000001" (ASRC Port B)
    ; bsf portA1Reg,6 ;set the mute bit in Port A #1 reg
    ; bcf LATC,5 ;Clear RC5 to Set XSMT(RC5) to zero for DAC soft mute
    ; call ASRCportA1Send ;Send the data to the ASRC to mute Port A
    ; call ASRCsrcSend ; send the value of srcCtlReg to the ASRC to set the source
    ; bcf portA1Reg,6 ;clear the mute bit in portA1Reg "00101001" for DIR, "00101011" for SRC
    ; call ASRCportA1Send ;Send the data to the ASRC to unmute
    ; call RPISend ;Update the RPI
    ; clrf knobFlag ;clear knobFlag for next interrupt
    ; bsf LATC,5 ;Set RC5 to Set XSMT(RC5) to one to un-mute DAC
    ; bsf LATC,4 ;Set RC4 high to notify the RPI of a need to send data
    ; return ;done!
    DIRSet: clrf rxReg ;Initialize the rxReg value to zero
    movlw 0x02
    subwf rxReg,f ;Set the rxReg value to correspond to srcCount-2
    movlw 00000010B ;set the SRC source to DIR
    bsf portA1Reg,6 ;set the mute bit in Port A #1 reg
    bcf LATC,5 ;Clear RC5 to Set XSMT(RC5) to zero for DAC soft mute
    ; call ASRCportA1Send ;Send the data to the ASRC to mute Port A
    ; call ASRCsrcSend ;send the data to the ASRC to set SRC to DIR
    ; call ASRCDIRSend ;send the data to the ASRC to set DIR to selected input
    bcf portA1Reg,6 ;clear the mute bit in portA1Reg "00101001" for DIR, "00101011" for SRCcall ASRCDIRSend ;Send the DIR data to the ASRC
    ; call ASRCportA1Send ;Send the data to the ASRC to unmute
    ; call RPISend ;Update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    bsf LATC,5 ;Set RC5 to Set XSMT(RC5) to one to un-mute DAC
    bsf LATC,4 ;Set RC4 high to notify the RPI of a need to send data
    return
    VolKnob: nop ;Determine CW or CCW Direction
    movlw 0x03 ;Mask for volume knob bits
    andwf knobState,1 ;mask off only vol bits in prior knob state
    andwf newKnobState,0 ;mask off only vol bits in current knob state
    movwf knbTemp ;save the new state in temp variable
    btfsc knbTemp,1 ;If bit 1 is set, then skip
    bsf STATUS,0 ;If bit 1 is set, then set carry bit in STATUS
    rlf knbTemp,1 ;shift new state (newKnobState) bits left (if Carry was set then it rotates in to bit 0 as Bit 1)
    movf knbTemp,w
    xorwf knobState,0 ;xor the new -in W- and prior knob state values
    movwf knbTemp
    btfsc knbTemp,1 ;if bit 1 is set, then turn was clockwise, so skip and increment
    goto VolDec ;otherwise turn was CCW, go decrement,
    VolInc: movf volMax,w ;check to see if volume is at max
    subwf volA,0
    btfsc STATUS,2
    goto NoVolChng ;if so, do nothing and return
    bcf volFlag,0 ;clear the volume flag (for increment)
    incf volA
    incf volB
    incf volC
    incf volD
    ; call DACVolSend ;go update DAC1 to change the volume
    ; call RPISend ;go update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    movlw 0x04 ;Set RC3 high
    addwf LATC ;Write the value to the port to notify the RPI of a need to send data
    return
    VolDec: movlw 0xFF
    addwf volA,0 ;check to see if volume is at min
    btfss STATUS,0
    goto NoVolChng ;if so, do nothing and return
    bsf volFlag,0 ;set volFlag (for decrement)
    decf volA
    decf volB
    decf volC
    decf volD
    ; call DACVolSend ;go update DAC1 to change the volume
    ; call RPISend ;go update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    movlw 0x04 ;Set RC3 high
    addwf LATC ;Write the value to the port to notify the RPI of a need to send data
    return
    NoVolChng: clrf knobFlag ;clear knobFlag for next interrupt
    return
    BalKnob: nop ;Determine CW or CCW Direction
    movlw 0x30 ;Mask for Balance knob bits
    andwf knobState,1 ;mask off only bal bits in prior knob state
    andwf newKnobState,0 ;mask off only bal bits in current knob state
    movwf knbTemp ;save the new state in temp variable
    btfsc knbTemp,5 ;If bit 5 is clear, then skip
    bsf knbTemp,3 ;If bit 5 is set, then set bit 3, to prepare for circular left shift
    rlf knbTemp,1 ;shift new state (newKnobState) bits left (if Bit 5 was set then it rotates in to bit 4 as Bit 5)
    movf knbTemp,w
    xorwf knobState,0 ;xor the new -in W- and prior knob state values
    movwf knbTemp
    btfsc knbTemp,5 ;if bit 5 is set, then turn was clockwise, so skip and increment balance
    goto BalDec ;otherwise turn was CCW, go decrement,
    BalInc: movf volMax,w ;check to see if volume is at max
    subwf volB,0
    btfsc STATUS,0
    goto NoBalChng ;if so, do nothing and return
    incf Bal,1 ;increment the balance value (so it can be saved for later in the RPI
    incf volB,1 ;and increase the VolB level by one step
    incf volD,1 ;and increase the VolD level by one step
    ; call DACVolSend ;go update DAC1 to change the volume
    ; call RPISend ;go update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    movlw 0x04 ;Set RC3 high
    addwf LATC ;Write the value to the port to notify the RPI of a need to send data
    return
    BalDec: movlw 0xFF
    addwf volB,0 ;check to see if volume B is at min
    btfss STATUS,0
    goto NoBalChng ;if so, do nothing and return
    incf Bal,1 ;Otherwise increment the balance value
    movf Bal,w
    decf volB,1 ;and reduce the VolB level by one step
    decf volD,1 ;and reduce the VolD level by one step
    ; call DACVolSend ;go update DAC1 to change the volume
    ;; call RPISend ;go update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    movlw 0x04 ;Set RC3 high
    addwf LATC ;Write the value to the port to notify the RPI of a need to send data
    return
    NoBalChng: clrf knobFlag ;clear knobFlag for next interrupt
    return
    EQKnob: nop ;Determine CW or CCW Direction
    movlw 0xC0 ;Mask for EQ knob bits
    andwf knobState,1 ;mask off only src bits in prior knob state
    andwf newKnobState,0 ;mask off only src bits in current knob state
    movwf knbTemp ;save the new state in temp variable
    btfsc knbTemp,3 ;If bit 7 is clear, then skip
    bsf knbTemp,1 ;If bit 7 is set, then set bit 5, to prepare for circular left shift
    rlf knbTemp,1 ;shift new state (newKnobState) bits left (if Bit 5 was set then it rotates in to bit 6 as Bit 7)
    movf knbTemp,w
    xorwf knobState,0 ;xor the new -in W- and prior knob state values
    movwf knbTemp
    btfsc knbTemp,7 ;if bit 7 is set, then turn was clockwise, so skip and increment EQ
    goto EQDec ;otherwise turn was CCW, go decrement EQ
    EQInc: movf volMax,w ;check to see if volume is at max
    subwf volB,0
    btfsc STATUS,2
    goto NoEQChng ;if so, do nothing and return
    incf Equal,1 ;increment the balance value to save inthe RPI
    incf volC,1 ;and increase the VolC level by one step
    incf volD,1 ;and increase the VolD level by one step
    ; call DACVolSend ;go update DACs to change the volume
    ; call RPISend ;go update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    movlw 0x04 ;Set RC3 high
    addwf LATC ;Write the value to the port to notify the RPI of a need to send data
    return
    EQDec: movlw 0xFF
    addwf volC,0 ;check to see if volume B is at min
    btfss STATUS,0
    goto NoEQChng ;if so, do nothing and return
    incf Equal,1 ;Otherwise increment the balance value
    movf Equal,w
    decf volC,1 ;and reduce the VolC level by one step
    decf volD,1 ;and reduce the VolD level by one step
    ; call DACVolSend ;go update DACs to change the volume
    ; call RPISend ;go update the RPI
    clrf knobFlag ;clear knobFlag for next interrupt
    movlw 0x04 ;Set RC3 high
    addwf LATC ;Write the value to the port to notify the RPI of a need to send data
    return
    NoEQChng: clrf knobFlag ;clear knobFlag for next interrupt
    return
    ;
    ;******************************************************************************
    ; SSP2_Handler
    ;******************************************************************************
    ;
    SSP2Handler:
    return
    ;
    ;******************************************************************************
    ; SSP1_Handler
    ;******************************************************************************
    ;
    SSP1Handler:
    return
    ;******************************************************************************
    ;
    END

    post edited by cogeniac - 2021/01/13 13:11:24
    #8
    mpgmike
    Super Member
    • Total Posts : 513
    • Reward points : 0
    • Joined: 2014/01/23 17:27:06
    • Location: NJ
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/13 12:42:45 (permalink)
    0
    Please use [ code ] at the start of your code and [/ code ] at the end (without the spaces).  This puts your code in a scrollable window, and adds color to key words, making it more manageable to read.

    I don't need the world to know my name, but I want to live a life so all my great-grandchildren proudly remember me.
    #9
    cogeniac
    Starting Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2017/02/04 19:50:39
    • Location: 0
    • Status: offline
    Re: IOC Issue using PIC 16LF18346 2021/01/13 13:12:42 (permalink)
    0
    Thanks mpg mike!!  Good to know!!
    #10
    Jump to:
    © 2021 APG vNext Commercial Version 4.5