1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

PIC18F25K42 a work in progress....

Discussion in 'Microcontrollers' started by granddad, Sep 29, 2017.

  1. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    After Mike-K8lH post
    http://www.electro-tech-online.com/threads/fyi-feature-rich-pic18fxxk42-series.151942/#post-1305813
    I read the data sheet, intro / features for the PIC18FxxK42 series, seemed a useful device , but has a lot of add-ons that required understanding … Having skipped the PIC18's for the 24F's seemed a interesting challenge.... a development project was born...
    phase1.jpg Screenshot42_1.jpg
    I am no programmer , and dislike libraries ( the soft sort ). so intend to code some device drivers.
    A couple of hours and the PIC18F25K42 had voltage and ICSP connections. A minimum C 'main' file ...and the scope confirmed CLKOUT pin at 16Mhz ( 64 / 4).


    Phase 1 , oscillator , delays and serial ….
     
    Last edited: Sep 29, 2017
  2. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,641
    Likes:
    109
    Location:
    Michigan, USA
    Yeah! Ok! Please keep me (us) posted.

    Just got my 18F26K42 DIP-28 samples and anxious to try one of 'em out but I have a couple other projects to finish first.

    Cheerful regards, Mike
     
  3. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    ( Please post if you spot errors / any corrections )

    Oscillator …Internal 64Mhz was set in configuration . Note ..Default seems to be LVP = ON so MCLRE = EXTMCLR
    Code (text):

    #pragma config FEXTOSC = OFF // External Oscillator Selection (Oscillator not enabled)
    #pragma config RSTOSC = HFINTOSC_64MHZ// Reset Oscillator Selection (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)
    // CONFIG1H
    #pragma config CLKOUTEN = OFF // Clock out Enable bit (CLKOUT function is disabled)
    #pragma config PR1WAY = ON // PRLOCKED One-Way Set Enable bit (PRLOCK bit can be cleared and set only once)
    #pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
    #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)

    // CONFIG2L
    #pragma config MCLRE = EXTMCLR // MCLR Enable bit (If LVP = 0, MCLR pin function is port defined function; If LVP =1, RE3 pin fuction is MCLR)
    #pragma config PWRTS = PWRT_OFF // Power-up timer selection bits (PWRT is disabled)
    #pragma config MVECEN = ON // Multi-vector enable bit (Multi-vector enabled, Vector table used for interrupts)
    #pragma config IVT1WAY = ON // IVTLOCK bit One-way set enable bit (IVTLOCK bit can be cleared and set only once)
    #pragma config LPBOREN = OFF // Low Power BOR Enable bit (ULPBOR disabled)
    #pragma config BOREN = SBORDIS // Brown-out Reset Enable bits (Brown-out Reset enabled , SBOREN bit is ignored)
    // CONFIG2H
    #pragma config BORV = VBOR_2P45 // Brown-out Reset Voltage Selection bits (Brown-out Reset Voltage (VBOR) set to 2.45V)
    #pragma config ZCD = OFF // ZCD Disable bit (ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
    #pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit (PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
    #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
    #pragma config DEBUG = OFF // Debugger Enable bit (Background debugger disabled)
    #pragma config XINST = OFF // Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)
    // CONFIG3L
    #pragma config WDTCPS = WDTCPS_31// WDT Period selection bits (Divider ratio 1:65536; software control of WDTPS)
    #pragma config WDTE = OFF // WDT operating mode (WDT Disabled; SWDTEN is ignored)
    // CONFIG3H
    #pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
    #pragma config WDTCCS = SC // WDT input clock selector (Software Control)
    // CONFIG4L
    #pragma config BBSIZE = BBSIZE_512// Boot Block Size selection bits (Boot Block size is 512 words)
    #pragma config BBEN = OFF // Boot Block enable bit (Boot block disabled)
    #pragma config SAFEN = OFF // Storage Area Flash enable bit (SAF disabled)
    #pragma config WRTAPP = OFF // Application Block write protection bit (Application Block not write protected)
    // CONFIG4H
    #pragma config WRTB = OFF // Configuration Register Write Protection bit (Configuration registers (300000-30000Bh) not write-protected)
    #pragma config WRTC = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
    #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
    #pragma config WRTSAF = OFF // SAF Write protection bit (SAF not Write Protected)
    #pragma config LVP = ON // Low Voltage Programming Enable bit (Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored)
    // CONFIG5L
    #pragma config CP = OFF // PFM and Data EEPROM Code Protection bit (PFM and Data EEPROM code protection disabled)

    #include <xc.h>
    #include <string.h>
    #include <stdlib.h>
    #define _XTAL_FREQ 64000000

     
    void OSC_init() , was coded for perhaps future changes.
    Delays... XC8 Has some built in delays , for example __delay_ms(100); __delay_us(100);
    Xtal frequency has to be defined as above ... A led / 470R was put on RB5 and the delays were tested … all good.

    Before establishing UART1 Serial, ( 2 available ) the PSS feature has to be understood , turns out is remarkably comprehensive and straight forward... and possibly more advanced than other PIC's (Note only digital can be multiplexed via PSS).

    Note PPS registers have a locking feature as per data sheet.

    PSS...Output..
    Step 1 . Where do I want the U1TX pin , RB6, RB7 are ICSP and the LED was on RB5, so RB4 .
    The PPS ( output ) has registers RxyPPS , for the 8 bit of the A,B,C ports so RB4PPS points to pin, to assign U1TX the value from the RxyPSS table ( Data Sheet * ) is coded …. ( any B or C port pins could have been used )
    [ 6'b01 0011 UART1 (TX) - B C ]

    PSS...Input.
    From Data Sheet
    -------------------------------------------------------------------------------------
    REGISTER 19-1: xxxPPS: PERIPHERAL xxx INPUT SELECTION
    bit 7-5 Unimplemented: Read as ‘0’
    bit 4-3 xxxPPS<4:3>: Peripheral xxx Input PORTx Pin Selection bits
    See Table 19-1 for the list of available ports and default pin locations.
    11 = Reserved
    10 = PORTC
    01 = PORTB
    00 = PORTA

    bit 2-0 xxxPPS<2:0>: Peripheral xxx Input PORTx Pin Selection bits

    111 = Peripheral input is from PORTx Pin 7 (Rx7)
    110 = Peripheral input is from PORTx Pin 6 (Rx6)
    101 = Peripheral input is from PORTx Pin 5 (Rx5)
    100 = Peripheral input is from PORTx Pin 4 (Rx4)
    011 = Peripheral input is from PORTx Pin 3 (Rx3)
    010 = Peripheral input is from PORTx Pin 2 (Rx2)
    001 = Peripheral input is from PORTx Pin 1 (Rx1)
    000 = Peripheral input is from PORTx Pin 0 (Rx0)
    ---------------------------------------------------------------------------------------

    PPS Inputs are logically reverse of outputs. The peripheral input has the register and the value assigns the pin via the xxxPPS table. U1 receive PPS register = b'01011 for RB3 pin.

    The respective TRIS bits were set in the IO_init()
    Result so far …
    Code (text):


    void OSC_init(){
     
    OSCFRQ=0x08; // 8=64 Mhz----0=1Mhz

    }

    void IO_init(){
    ANSELA=0; // all digital
    ANSELB=0; // all digital
    ANSELC=0; // all digital
    TRISBbits.TRISB5=0; // led
    TRISBbits.TRISB4=0; // U1TX
    TRISBbits.TRISB3=1; // U1RX
    LATBbits.LATB5=1; // Turns the led on
    }

    void PPS_init(){
    RB4PPS=0x13; // RB4 = UART1 TX.
    U1RXPPS=0x0B; // RB3 = UART1 RX
    }

     
    ( I come from machine code so use HEX a lot ! )

    Break here to solder on a FTDI and swat up on UART ....

    Note , After reading the mountain of K42 'Features' it is obvious I will not be able to cover everything. The idea was more of a launch pad, to see the mcu's project possibilities.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK

    The K42 UARTs are again comprehensive in the settings, lots of interrupt flags and, options , so this is just a basic serial test of TX . RX and its interrupt to follow...

    Perhaps not the best 'C' way to code initialization for UART 1...

    All the registers from the UART section of the data sheet ( Its a good idea to read the 'Register and bit naming conventions') were set initially at 0; and a clean/build to see if correct. Then the basic 8,N,1,19200 bits were set.

    Code (text):

    void UART_init(){
    U1BRG=207; // SET BAUD OF 19200 for 64Mhz Fosc.
    //U1CON0
    U1BRGS=0; // Baud speed clock / bits
    U1ABDEN=0; // en auto baud
    U1TXEN=1; // TX enable
    U1RXEN=1; // RX enable
    U1CON0bits.MODE=0;// 8,N,1 mode
    //U1CON1
    U1ON=1; // U1 serial port enabled
    U1WUE=0; // Wake up bit enable
    U1RXBIMD=0; // RX break int mode
    U1BRKOVR=0; // Break override
    U1SENDB=0; // send break
    //

    //U1CON2
    U1RUNOVF=0; // Run in overflow
    U1RXPOL=0; // RX polarity
    U1CON2bits.STP=0; // =1 Stop bit,
    U1C0EN=0; // Check sum mode bits
    U1TXPOL=0; // TX polarity
    U1CON2bits.FLO=0; // Flow ctrl off
    //
    U1ERRIR=0x00; // error flags
    //
    // U1ERRIE // UART1 INTERRUPT ENABLE
    U1TXMTIE=0; // TX empty
    U1PERIE=0; // Parity err
    U1ABDOVE=0; // Auto baud detect
    U1CERIE=0; // Check sum err
    U1FERIE=0; // Frame err
    U1RXBKIE=0; // Break received
    U1RXFOIE=0; // FIFO overflow
    U1TXCIE=0; // TX collision
    PIE3bits.U1RXIE=0; //RX interrrupt enable
    PIE3bits.U1TXIE=0; //TX interrrupt enable
    PIE3bits.U1EIE=0; //Frame err interrrupt enable
    PIE3bits.U1IE=0; //UART1 interrrupt enable
    }

    void serial_print(unsigned char *Pline,int nl)
    {
    int x = 0;
    for ( x = 0; Pline[x]!=0x00 ; x++)
    {
    while (U1TXMTIF == 0) {}
    U1TXB = Pline[x];
    }
    while (U1TXMTIF == 0 ) {}
    if(nl) U1TXB = 0x0D ; // new line
    }
     
    'main' to do a simple serial test ... Hyper terminal screen shot … all good :)

    Code (text):

    int main(void) {
    OSC_init();
    IO_init();
    PPS_init();
    UART_init();
    __delay_ms(100);
    serial_print(" The answer to Life the Universe and Everything ? ",1);
    serial_print("= K42 ",0);

    while(1){}
    return ;
    }
     
    I have always found I2C useful, either saving IO pins , or linking boards.
    I have a small 2x16, I2C LCD wired up in my parts box, so next is K42 and I2C, the aim is to send from HyperTerminal to the LCD . I have a load of I2C code written for other PIC's so will try to import and see how it goes...
    K42ftdi.jpg ht42.jpg
     
  6. JLNY

    JLNY Active Member

    Joined:
    Mar 5, 2011
    Messages:
    220
    Likes:
    35
    Location:
    New York, USA
    Fun stuff-- will definitely keep an eye on this thread. I too tend to have an aversion to libraries when I have the option to set the registers myself. Perhaps more due to stubbornness in doing things myself than any belief that I am a better programmer or less prone to mistakes than the people making the libraries. :p

    Not sure if this would be of much use to anyone, but I did a quick-and-dirty development board layout in Eagle a little while back for the PIC16F1778, which just so happens to have an identical pinout to the PIC18F2#K42 chips. I recently ordered a couple 26K42 TSSOP chips, so I may give one a try on a leftover test board to see if it works.
     

    Attached Files:

    • Thanks Thanks x 1
  7. JLNY

    JLNY Active Member

    Joined:
    Mar 5, 2011
    Messages:
    220
    Likes:
    35
    Location:
    New York, USA
    A quick update to the post above: I soldered up a couple of 26K42s onto my 16F1778 boards, and I can confirm that they seem to work and program just fine. I haven't checked all the pins, but they should be the same. I was able to bang out a crude blink program using a quick-and-dirty delay function on timer 2.

    I'm sure my code is likely to have errors or just generally be sloppy, so feel free to suggest corrections where necessary. I am using an 8MHz crystal with the x4 PLL for 32MHz, because the 16F1778s I was using with these boards were only rated to 32MHz instead of 64MHz, so you will need to change T2CON to 0x70 for a 64MHz Fosc.

    Code (text):

    // CONFIG1L
    #pragma config FEXTOSC = HS     // External Oscillator Selection (HS (crystal oscillator) above 8 MHz; PFM set to high power)
    #pragma config RSTOSC = EXTOSC_4PLL// Reset Oscillator Selection (EXTOSC with 4x PLL, with EXTOSC operating per FEXTOSC bits)

    // CONFIG1H
    #pragma config CLKOUTEN = OFF   // Clock out Enable bit (CLKOUT function is disabled)
    #pragma config PR1WAY = ON      // PRLOCKED One-Way Set Enable bit (PRLOCK bit can be cleared and set only once)
    #pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
    #pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor enabled)

    // CONFIG2L
    #pragma config MCLRE = EXTMCLR  // MCLR Enable bit (If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR )
    #pragma config PWRTS = PWRT_OFF // Power-up timer selection bits (PWRT is disabled)
    #pragma config MVECEN = ON      // Multi-vector enable bit (Multi-vector enabled, Vector table used for interrupts)
    #pragma config IVT1WAY = ON     // IVTLOCK bit One-way set enable bit (IVTLOCK bit can be cleared and set only once)
    #pragma config LPBOREN = OFF    // Low Power BOR Enable bit (ULPBOR disabled)
    #pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled , SBOREN bit is ignored)

    // CONFIG2H
    #pragma config BORV = VBOR_2P45 // Brown-out Reset Voltage Selection bits (Brown-out Reset Voltage (VBOR) set to 2.45V)
    #pragma config ZCD = OFF        // ZCD Disable bit (ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
    #pragma config PPS1WAY = ON     // PPSLOCK bit One-Way Set Enable bit (PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
    #pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
    #pragma config DEBUG = OFF      // Debugger Enable bit (Background debugger disabled)
    #pragma config XINST = OFF      // Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)

    // CONFIG3L
    #pragma config WDTCPS = WDTCPS_31// WDT Period selection bits (Divider ratio 1:65536; software control of WDTPS)
    #pragma config WDTE = OFF       // WDT operating mode (WDT Disabled; SWDTEN is ignored)

    // CONFIG3H
    #pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
    #pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

    // CONFIG4L
    #pragma config BBSIZE = BBSIZE_512// Boot Block Size selection bits (Boot Block size is 512 words)
    #pragma config BBEN = OFF       // Boot Block enable bit (Boot block disabled)
    #pragma config SAFEN = OFF      // Storage Area Flash enable bit (SAF disabled)
    #pragma config WRTAPP = OFF     // Application Block write protection bit (Application Block not write protected)

    // CONFIG4H
    #pragma config WRTB = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-30000Bh) not write-protected)
    #pragma config WRTC = OFF       // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
    #pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
    #pragma config WRTSAF = OFF     // SAF Write protection bit (SAF not Write Protected)
    #pragma config LVP = ON         // Low Voltage Programming Enable bit (Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored)

    // CONFIG5L
    #pragma config CP = OFF         // PFM and Data EEPROM Code Protection bit (PFM and Data EEPROM code protection disabled)

    // CONFIG5H

    #include <xc.h>
    #include <PIC18F26K42.h>

    volatile int t = 0;

    void init(){
     
        TRISB = 0x7E; //B7 as output
        LATB = 0x80;
     
        T2CLK = 0x01; //clock source = Fosc/4, Fosc = 32MHz = 8MHz*4xPLL
        //T2HLT = 0x00; //rising edge triggered, free running with software gate
        T2CON = 0x60; //T2 off, /64 prescaler, 1:1 postcaler (125KHz)
        T2PR = 125; //125KHz/125=1KHz or 1ms delay
     
        T2TMR=0;     //clear TMR2 counter
        TMR2IF = 0; //clear TMR2 interrupt flag
        GIE = 1; //global interrupts enabled
        TMR2IE = 1; //T2 interrupt enabled
     
    }

    void delay_millis(int time){
        t=time;
        T2TMR=0;
        T2ON=1;
        while(t>0);
        T2ON=0;
    }

    void main(void) {
     
        init();
     
        while(1){
            delay_millis(1000);
            LATB ^= 0x80;
        }
     
        return;
    }

    void __interrupt (irq(IRQ_TMR2)) TMR2_ISR(void){
        TMR2IF = 0;
        t--;
    }
     
     

    Attached Files:

  8. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    Hi JLNY , that is a nifty little board. I have not achieved I2C yet ( still having to do other things ) . Was wondering how to do Interrupt on K42 , looks like I have more stuff to learn . on PIC24 and XC16 was "simple-ish " ....
     
  9. JLNY

    JLNY Active Member

    Joined:
    Mar 5, 2011
    Messages:
    220
    Likes:
    35
    Location:
    New York, USA
    Hehe, thanks! Yeah, I don't have much experience with vectored interrupts on PICs, so the syntax is still a bit alien to me. I mostly just copied the example on the datasheet.
     

    Attached Files:

  10. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    :facepalm: I just now see there are 19 registers associated with I2C ..... See you next year :eek:

    Edit... Well , I2C has all changed from my previous pic stuff with the K42 , no waits just load I2C TX the buffer and that's it ... or is it ...
     
    Last edited: Oct 5, 2017
  11. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    In my experience I2C has always been about timing ... likewise LCD has always been about timing , so my I2C + Lcd mix is ... you guessed it... Timing x 2 !
    I have a result on the display of (1) sending the I2C Lcd init string ... and (2) sending a message string .....

    CEG_2.jpg

    And I have a timing issue as I sent "ABCDE1234" . Init appears to work... characters not..

    It took some time to get here , the MC document TB3159 I2C Communications with Hardware Protocol Acceleration on 8-Bit PIC® Microcontrollers , was a help as it has examples , ( K42 data sheet = contradictions about I2C port pins open collector settings ). But think I need to find a slower I2C clock.... this is @ 500Khz all other options I think are faster ...( wrong)

    Edit since realised 500khz = 125khz SCL Have reached a sometimes it does then it does not...
     
    Last edited: Oct 7, 2017
  12. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    Result !
    For a 'C' amateur like me the K42 does I2C somewhat easier than previous PIC I2C peripherals , re checking ACKSTAT , and start bits etc...

    My eventual result.... to initialise a I2C-2x16 LCD and send a message.
    I2C initialise... Lots of bits here .. cut it down to the very minimum .

    Code (text):


    void I2C_init(){    // ---7---|---6---|---5---|---4---|---3---|---2---|---1---|---0---|
                       //   --      --      --      --      --          BTO<2:0>          
    I2C1BTO =0;         //    0       0       0       0       0       0       0       0
                       //   --      --      --      --      --          CLK<2:0>        
    I2C1CLK =0x03;      //    0       0       0       0       0       0       1       1  
                       //  CNTIE   ACKTIE   --     WRIE    ADRIE   PCIE    RSCIE    SCIE
    I2C1PIE =0;         //    0       0       0       0       0       0       0       0
                       //  CNTIF   ACKTIF          WRIF    ADRIF   PCIF    RSCIF    SCIF
    I2C1PIR =0;         //    0       0       0       0       0       0       0       0
                       //   --     BTOIF   BCLIF  NACKIF    --     BTOIE   BCLIE   NACKIE
    I2C1ERR =0;         //    0       0       0       0       0       0       0       0
                       //  BFRE     SMA     MMA      R       D      --      --      --
    I2C1STAT0 =0;       //    0       0       0       0       0       0       0      0
                       //  TXWE     --     TXBE     --      RXRE   CLRBF    --      RXBF
    I2C1STAT1 =0;       //    0       0       0       0       0       0       0      0
                       //   EN      RSEN     S     CSTR      MDR        MODE<2:0>
    I2C1CON0 =0x04;     //    0       0       0       0       0       1       0      0
                       // ACKCNT   ACKDT  ACKSTAT  ACKT     --      RXOV     TXU     CSD
    I2C1CON1 =0x80;     //    1       0       0       0       0       0       0      0
                       //  ACNT    GCEN     FME     ADB*     SDAHT<3:2>     BFRET<1:0>
    I2C1CON2  =0x31;    //    0       0       1       1       0       0       0      1
    I2C1ADR0  =0;       // ADR<7:0>                *addr buf disabled
    I2C1ADR1  =0;       // ADR<7:1>
    I2C1ADR2  =0;       // ADR<7:0>
    I2C1ADR3  =0;       // ADR<7:1>
    I2C1ADB0  =0;       // ADB<7:0>
    I2C1ADB1 =0;        // ADB<7:0>
    I2C1CNT  =0;        // CNT<7:0>
    I2C1RXB  =0;        // RXB<7:0>
    I2C1TXB =0;         // TXB<7:0>
    I2C1CON0bits.EN = 1; // enable I2C module
    }
     
    If the auto address buffer is enabled * I2C1CON2 then start bit sequence is different to my code , I could not get this to work, so went with it disabled . I2C clock is derived from a 500khz osc. /4 = 125khz.

    Also not sure to load TX buffer then wait on empty flag or wait then load after start bit . As the address is still in TX buffer , did the later.

    HW , set up.. I have 2k2 pull-ups on data and clock but could have had internal .
    I also mistakenly called IO_init before PPS_init. This gave a short spike to lines before I2C took control, not good :(

    Code (text):


    void IO_init(){
       ANSELA=0; // all digital
       ANSELB=0; // all digital
       ANSELC=0; // all digital
       TRISBbits.TRISB5=0;
       LATBbits.LATB5=1;   //led on
       // Configure the pins as Open-drain
       ODCONCbits.ODCC3 = 1;
       ODCONCbits.ODCC4 = 1;
       // Set the I2C levels
       RC3I2Cbits.TH = 1;
       RC4I2Cbits.TH = 1;
       // Configure the pins as Outputs
       TRISCbits.TRISC3 = 0;
       TRISCbits.TRISC4 = 0;
     }

    void PPS_init(){   // do PPS before IO_init();
       //UART1
       RB4PPS=0x13; // RB4 = UART1 TX.
       U1RXPPS=0x0B; // RB3 = UART1 RX
       // Set RC4 for SDA1
       RC4PPS = 0x22;
       I2C1SDAPPS = 0x14;
       // Set RC3 for SCL1
       RC3PPS = 0x21;
       I2C1SCLPPS = 0x13;

    }

     
    Basic K42 sending of I2C data... ( address buffer disabled )
    load count with bytes to send.
    Load device address for write ! to the TX buffer
    Set the start bit.
    loop
    Wait for the TX buffer empty
    load the data byte
    loop if count not zero
    when count is zero and buffer empty stop bit is automatically sent

    Any errors will set a interrupt flag for an error routine .

    This Blue / white Midas I2C display has extended controls similar to the standard lcd HD44780 chip .

    Code (text):


    void LCD_init()
    {
      unsigned int x;
      I2C1CNT=0x08;     // load I2C1CNT with number of INIT bytes  
      I2C1TXB = 0x7C;   // load addr
      I2C1CON0bits.S=1; // set start
      for(x=0;x<8;x++){
      while(!I2C1STAT1bits.TXBE){}  // wait for buffer empty
      I2C1TXB = LCD_init_data[x];
      }
      __delay_ms(200);
    }  

    void send_I2C_lcd(char *message, unsigned char Lpos)  // send message at line + location
    {
      LCD_loc(Lpos) ;
      unsigned int x;
      unsigned int sendlen;
      sendlen= strlen(message);
      I2C1CNT=sendlen + 1;        // load I2C1CNT with number of bytes  
      I2C1TXB=0x7C;               // load I2C1TXB with device address
      I2C1CON0bits.S=1;     // set start
      while (!I2C1STAT1bits.TXBE);  // wait for buffer empty
      I2C1TXB = 0x40;               // load control byte
      for(x=0;x<sendlen;x++){
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = message[x];        // load next message byte
      __delay_ms(1);
      }
    }

    void LCD_loc(unsigned char Lpos) // line 1 0x80 to 0x8F
    {                                                      // line 2 0xC0 to 0xCF  
      unsigned int x;
      I2C1CNT=0x02;      //  load I2C1CNT with number of bytes  
      I2C1TXB=0x7C;       // load I2C1TXB with device address
      I2C1CON0bits.S=1; // set start
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = 0x00;        // load next byte
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = Lpos;        // load next byte
      __delay_ms(1);
    }

     
    K42 Phase 2...or is it 5 !

    RX from UART , this requires an interrupt..... more new ground .
     
  13. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    The UART interrupt stumped me for some time , seems you cannot clear the U1RX interrupt flag without first reading the receive buffer , then it all behaves as it should , and keyboard input from the PC, gets via FTDI chip into PIC.. then out to I2C display... job done …K42 UART's have a FIFO but not looked at that yet, I2C reading has not been included either . I have a DS1338 RTC module , so Phase 6 = to put the time / date on the display...

    phase5.jpg

    Interrupt stuff....

    Code (text):


    void __interrupt(irq(IRQ_U1RX)) U1RX_ISR()
    {
    LATBbits.LATB5=1;   //led on
    Serial_in=1;        // flag main to send to lcd
    byte_in=U1RXB;     / get the byte
    PIR3bits.U1RXIF = 0; // Clear the interrupt flag
    }

    void __interrupt(irq(default)) DEFAULT_ISR()
    {
    while(1); // Unhandled interrupts go here
    }

    void INTERRUPT_Initialize(void)
    {
     INTCON0bits.GIEH=1; // Global int enable
     INTCON0bits.GIEL=0; //  
     INTCON0bits.IPEN=0; // Interrupt priority not used

     PIE3bits.U1RXIE=1;  // Enable U1RX INTERRUPT
     IPR3bits.U1RXIP=0;  //  

     IVTBASEU=0x00;     // default 0x000008
     IVTBASEH=0x00;     //
     IVTBASEL=0x08;     //
    }

     
     
  14. jpanhalt

    jpanhalt Well-Known Member Most Helpful Member

    Joined:
    Jun 21, 2006
    Messages:
    5,978
    Likes:
    510
    Location:
    Cleveland, OH, USA
    I think that behavior is pretty common across the PIC lines. For example, RCIF in the 16F versions is read only and is cleared by reading the buffer, i.e., clearing the interrupt event.

    John
     
    • Thanks Thanks x 1
  15. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    john.... agree, I think I have been coding [ read RX then reset flag ] (pic16,18, 24 ) that way and not realised it .... the MC example I pasted was a TMR0 interrupt and it reset the flag on first line, I just changed the names etc hence my difficulty...
     
  16. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    Time and Date from DS1338 module. (This has battery backup)

    Adding the DS1338 module to the board, caused a load of problems. And it took me some time with the Bus Pirate and a laptop and scope , to realise how dopey , slipshod I can be ! I have always used 2k2 pullup on I2C , I have seen other “standards” like 4k7 ,10k etc , I am thinking it depend on clock speed and line capacitance , to cut this post short the DS... ACK to write data was sometimes being seen as NACK by the PIC, (scope showed a ACK at a highish level )and resulted in all sorts of automatic stops / restarts etc... because I actually had two sets of pullups installed ! A pair of 2k2 on my board and 10k's on the RTC … result 1k7 ish. After the penny dropped , I had loads of fun sending control and data back and forth....Had to change the I2C init to address buffer enabled , as below.

    The smart C guys will see lots of better code solutions , but this was my no fancy definitions time, to make sure it worked as required. The signal out from the DS will be used to trigger an interrupt to update the display (60 sec) . This could be done several ways , but as K42 has TxCLKIPPS ( timer x clock input to a pin ), thinking be a good way to achieve it with timer 3 on port RB2. Edit decided better with timer 0..

    Note to self … assume nothing !


    phase61.jpg




    Code (text):

    // info
    //char RTC_I[]={0x00,0x00,0x38,0x15,0x04,0x18,0x10,0x17,0x10};
    //Ds1338  start-reg   sec  min  hrs  day# Day  Mth  Year out

    void RTC_get_DateTime(char *Time_date)
    {
      unsigned int x;
      I2C1CNT=0x01;     // load I2C1CNT with number of bytes
      I2C1ADB1 = 0xD0; //RTC_write;   // load addr
      I2C1TXB = 0x00;   // write 0x00 start addr and tx byte
      while(!I2C1PIRbits.PCIF); // WAIT FOR STOP.
      I2C1CNT=0x08; // load I2C1CNT with number of bytes
      I2C1ADB1= 0xD1;  // RTC_read;     // load addr
      I2C1CON0bits.S=1; // set start
      for(x=0;x<8;x++){  // loop while reading
      while(!I2C1STAT1bits.RXBF); // RX test
       *Time_date = I2C1RXB; // update data
       Time_date++; // advance pointer
       }
    }

    {
     // fast mode , address buffer enabled , T2 is bus timeout

    void I2C_init(){    // ---7---|---6---|---5---|---4---|---3---|---2---|---1---|---0---|
                       //   --      --      --      --      --          BTO<2:0>          
    I2C1BTO =0x01;      //    0       0       0       0       0       0       0       1
                       //   --      --      --      --      --          CLK<2:0>        
    I2C1CLK =0x03;      //    0       0       0       0       0       0       1       1  
                       //  CNTIE   ACKTIE   --     WRIE    ADRIE   PCIE    RSCIE    SCIE
    I2C1PIE =0;         //    0       0       0       0       0       0       0       0
                       //  CNTIF   ACKTIF          WRIF    ADRIF   PCIF    RSCIF    SCIF
    I2C1PIR =0;         //    0       0       0       0       0       0       0       0
                       //   --     BTOIF   BCLIF  NACKIF    --     BTOIE   BCLIE   NACKIE
    I2C1ERR =0;         //    0       0       0       0       0       0       0       0
                       //  BFRE     SMA     MMA      R       D      --      --      --
    I2C1STAT0 =0;       //    0       0       0       0       0       0       0      0
                       //  TXWE     --     TXBE     --      RXRE   CLRBF    --      RXBF
    I2C1STAT1 =0;       //    0       0       0       0       0       0       0      0
                       //   EN      RSEN     S     CSTR      MDR        MODE<2:0>
    I2C1CON0 =0x04;     //    0       0       0       0       0       1       0      0
                       // ACKCNT   ACKDT  ACKSTAT  ACKT     --      RXOV     TXU     CSD
    I2C1CON1 =0x80;     //    1       0       0       0       0       0       0      0
                       //  ACNT    GCEN     FME     ADB*     SDAHT<3:2>     BFRET<1:0>
    I2C1CON2  =0x21;    //    0       0       1       0       0       0       0      1
    I2C1ADR0  =0;       // ADR<7:0>                *enabled
    I2C1ADR1  =0;       // ADR<7:1>
    I2C1ADR2  =0;       // ADR<7:0>
    I2C1ADR3  =0;       // ADR<7:1>
    I2C1ADB0  =0;       // ADB<7:0>
    I2C1ADB1 =0;        // ADB<7:0>
    I2C1CNT  =0;        // CNT<7:0>
    I2C1RXB  =0;        // RXB<7:0>
    I2C1TXB =0;         // TXB<7:0>
    I2C1CON0bits.EN = 1; // enable I2C module
    }


    void LCD_init()
    {
      unsigned int x;
      I2C1ADB1 = 0x7C;   // load addr  7c
      I2C1CNT=0x08;     // load I2C1CNT with number of INIT bytes  
      for(x=0;x<8;x++){
      I2C1TXB = LCD_init_data[x];  // send data
       while(!I2C1STAT1bits.TXBE); // wait for buffer empty
       }
      while(!I2C1PIRbits.PCIF); // WAIT FOR STOP.
      __delay_ms(100);
    }  


    void DS1338_init()
    {
      unsigned int x;
      I2C1CNT=0x09;     // load I2C1CNT with number of INIT bytes
      I2C1ADB1 = 0xD0;   // load addr  7c
      for(x=0;x<9;x++){
      I2C1TXB = RTC_I[x];
       while(!I2C1STAT1bits.TXBE); // wait for buffer empty
       }
      while(!I2C1PIRbits.PCIF); // WAIT FOR STOP.
      __delay_ms(1);
    }  


    void send_I2C_lcd(char *message,unsigned char Lpos)  /// send message at line + location
    {
      LCD_loc(Lpos);
      unsigned int x;
      unsigned int sendlen;
      sendlen= strlen(message);
      I2C1ADB1=0x7C;               // load I2C1TXB with device address
      I2C1CNT=sendlen + 1;        // load I2C1CNT with number of bytes  
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = 0x40;               // load control byte
      for(x=0;x<sendlen;x++){
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = message[x];        // load next message byte
      }
      while(!I2C1PIRbits.PCIF); // WAIT FOR STOP.
      __delay_ms(1);
    }

    void LCD_loc(unsigned char Lpos) // line 1 0x80 to 0x8F
    {                                // line 2 0xC0 to 0xCF  
      unsigned int x;
      I2C1ADB1=0x7C;       // load I2C1TXB with device address
      I2C1CNT=0x02;      //  load I2C1CNT with number of bytes  
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = 0x00;        // load next byte
      while (!I2C1STAT1bits.TXBE); // wait for buffer empty
      I2C1TXB = Lpos;        // load next byte
      __delay_ms(1);
    }
     
     
    Last edited: Oct 19, 2017
  17. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    I have learnt quite a bit trying to get the time to roll over from a T0 (timer 0 ) interrupt ,
    Scenario
    I2C , IO , T0 , display Interrups all initialised OK
    Date and time fetched OK
    Displayed OK
    T0 interrupt roll over set to match count of 59 DS is output 1 Hz ( PIC weak pull up )
    60 second later T0 Interrupt set ..
    Date and time fetched OK

    Display I2C Crash......... K42 has stop condition flag set writing the LCD address.
    Lots of tweaking ... depression... midnight oil...
    Previous post .... I had pullups too low , Realised now 10k pullup not good either , with a mpu running at 16 MIPS.
    Conclusion After I2C fetch of date time , with 10k installed bus needs several u_sec to recover to high level , put in a __delay_us(100) at end of ... void RTC_get_DateTime(char *Time_date) now works fine. Scope also shows very poor square SCL / SDA so going back to 2k2 .

    Edit well decided to try 4k7 pullups as i had a couple of smd , the display seems to have trouble in pulling the Data low for the ACK... I also reduced the delay to 50 usec ...anyway is working. Read from RTC
    DS1Z_2.jpg
    Write to display
    DS1Z_1.jpg
     
    Last edited: Oct 25, 2017
  18. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    I am aware I have coded I2C for what 'Should' happen broke the rules by not coding for what 'Could' happen. Given the quantity of I2C condition interrupt flags it will be possible to write a function(s) to cover all of the 'Coulds " and recover from errors.

    I have since realised it may have been better on this occasion to read the LCD Busy flag before sending to it, as timing seem to vary quiet a bit with this display .

    Phase 7 I will attack K42's AD , I have a "Dfrobot" moisture sensor , still waiting for some volts to be applied ,
     
    • Like Like x 1
  19. jpanhalt

    jpanhalt Well-Known Member Most Helpful Member

    Joined:
    Jun 21, 2006
    Messages:
    5,978
    Likes:
    510
    Location:
    Cleveland, OH, USA
    Nice work. Thanks for the update.

    John
     
  20. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,290
    Likes:
    647
    Location:
    Derbyshire, UK
    I'm a bit confused as to why you're using a timer interrupt? - is it just to read the clock chip at regular intervals?.

    Easiest solution, and what I do, is configure the DS to output a 1 sec pulse, and feed that to an I/O interrupt pin - this makes it simple to automatically update the display every time the seconds tick over.
     
    • Like Like x 2
  21. granddad

    granddad Active Member

    Joined:
    Jan 18, 2015
    Messages:
    758
    Likes:
    76
    Location:
    Worcestershire UK
    Nigel, Fair point , I am not displaying the seconds , and the project is just to evaluate the K42 series, int from T0 was just an exercise , the PPS and the 7 (4) timers with this pic are feature rich , I am usually 'playing' with Pic24 trying to find a a pin or a clock frequency. One thing I will add , I have this project / IDE v4.0 etc running on linux mint , and it seems way better than on windows. point 2 Do Rigol really charge 180 quid to licence I2c trigger and decode, My 30 hours nearly up :( ....
     

Share This Page