Showing posts with label PIC18F26Q71. Show all posts
Showing posts with label PIC18F26Q71. Show all posts

Thursday, May 4, 2023

RN4020 to RN4871 Update

 


I have had my head down while trying to make this transition that I described briefly in this post.  I have had some success and learned a few things along the way.  

I am no BTLE expert and I have tried to slug through the specifications, but it is a tough read for those of us who don't do this on a daily basis.  The RN4020 was 4.2 and the RN4871 says it is 5.0 and beyond.  I am assuming that some enhanced features were added.  My Android code was quite dependent on this real time read feature of the RN4020.  Without this, getting data back was difficult.  

After some reading, I implemented the Notification feature for each characteristic.  I had done this with the Heartbeat characteristic, but now all of the characteristics have this enabled.  This will also enable me to continue to support existing Brick Buddy I controllers.  The Android APP tested to see if Notifications are enabled on the Brick Buddy.  If they are, the new code is implemented, otherwise the Android APP stays with the old methodology.  So now I write to the Characteristic, the 18F26Q71 performs the tasks, updates the characteristic value and then notifies the Android APP the characteristic has changed.  The APP is waiting (in a separate thread) for a few seconds for the 18F26Q71 to respond (plenty of time at 64MHz).

Next issue was finding the the Brick Buddy during scanning.  The Android APP had implemented a scan search on the MyMakerTools UUID.  While it continues to work for RN4020 devices, it failed on all RN4871 devices.  I could scan for it along with every other BTLE device in the house and the neighborhood.  Sometimes I would see 20 devices.  At first I thought this was an issue with the Delphi compiler.  After tracing deep into the library, I decided this was not the issue.  This must be something to do with advertising.  Again, not a BTLE expert and if the spec changed, then I was not seeing it.  I found a note in a RN4870/4871 firmware upgrade document that said:

This led to lots of reading on the NA command, which is about advertising.  So in the RN4871, you have to purposely advertise services.  If the Android APP is filtering on a specific service list, those services must be advertised.  If not filtering on a specific service list, then all reachable BTLE devices show up.  The system will still connect, but it is multi step process that should just happen.

So here is the initialization of the RN4871 across the ASCII UART interface.  Will another sequence work, probably, but I know this works.

  • PZ
  • NA,Z  
reboot here
  • SS,80            ; setup
  • SN,B-Buddy       ; device name
  • SDN,MyMakerTools ; mfg name
  • PS,3425a5cca67643629592a88e132b8b52       ;service
  • PC,b67e3a3b15c941b6a9f2fbf379418d12,12,02 ;characteristic
  • PC,f18e901af3254dfd8cdb68506676dc08,16,08 ;characteristic
  • PC,9bac1d289fc14db097c4896089ad26bb,16,08 ;characteristic
  • PC,39bb1bf917ec41d2b5e4b78551b45740,06,08 ;characteristic
  • NA,01,06         ; set flags
  • NA,07,528b2b138ea89295624376a6cca52534    ;advertised service
  • A                ; turn on advertising


 The first two clear out the services/characteristics and the advertisement data, followed by a reboot.  The next are setup and naming, followed by the service and the characteristics.  The first NA command sets the flags.  The first hex value is the AD Type which is found in Table 2-14 of the RN4870/71 Users Guide.  The next is an 8 bit value that reflects which flags are active.  You will need to search the internet to find this, but 0x06 is the most common value.  The last NA command is the advertised service.  You will notice that is does not match the service.  For whatever reason, the NA, 07 command will not take the value as the PS command does, it needs to be completely byte swapped.  Not the most user friendly, but probably made sense to someone.  Finally I purposely started advertising.  This is supposed to be the default, but it costs very little.  I did not test the initialization without this, so I don't know if the default is works also.

I am back to where I was with the RN4020.  I still need to verify the Android APP with the original Brick Buddy, but that is a task for another day.


 

 

Tuesday, May 2, 2023

Upgrading from RN4020 to RN4871

 


 I am in the process of upgrading the wireless interface for those people who want to install it.   I was hoping that moving from the RN4020 to the RN4871 would be simple and painless.  As is always the case now, it was not.

I use the ASCII interface over a standard serial UART.  While most of the commands are the same, there are changes.

  1. They have included a delimiter on all GATT messages (%) plus a few others.  While it makes the parsing a little easier, it changed the way the parser worked.  
  2. The RN4871 is very sensitive to power and the reset input (see this post).  When I designed Brick Controller 3, I used the PIC nMCLR input to reset the RN4871.  This in turn is driven by TC54 reset controller.  So that part is good, since it appears the RC type resets don't work.  I do have a spare GPIO now, so I could cut/jump that in if it becomes necessary.
  3. There is a transparent UART mode, but I am not sure how much Android work that will entail, if it is even possible.
  4. The most important change was the elimination of the real time read mode.  The mode would send a message across the UART that the phone was about to read the characteristic.  This would allows the PIC just enough time to update the characteristic value before the phone read it.  That is not implemented in the RN4871.  So I am looking at other ways to do this.

I mostly have the interface working.  It seems to be stable, though the code needs some work.  The 18F26Q71 running at 64MHz, is just too fast for a 115200 baud rate.  During initialization, I have to make sure that the RN4871 response has come in before moving on to another command.  While this implemented in essentially "wait for it to happen" code, this needs to move into the switch function of the BT_TASKS subroutine of the main loop.


 

 

 

 

Monday, April 10, 2023

Brick Buddy 3 Its Alive

 

Well kind of.  The light flashes (see yellow arrow) which means the main loop is working.  As you can see all of the through hole connectors need to be installed and a few other parts.  I can start testing the LED control right a way and then move on to motor control.  The only mistake so far is on the back side.  I added an I2C EEPROM for more memory storage of scripts.  This type of memory does not have the restrictions on it as does using any left over program flash for this purpose.  The clip holds the Tag-Connect ICSP connection for the PICKit.  For now I am using the on chip EEPROM.  When the time comes, I will "jury rig" something to make the connection and have the memory.

But the first day was a roller coaster.  It works then it doesn't.  And it all came down to writing internal EEPROM with the debugger attached.  This is FYI for anyone using PIC18FxxQxx processors, but might apply to K processors also.  

I added the FTDI part (did not have the assembler do any backside parts), Windows recognized the FTDI part and my Brick Controller PC APP that controls all my boards connected just fine.  I needed to do some Win APP updates for this board, so I downloaded the firmware just to reduce the variables.  This is the same base code that runs in all boards.

It downloaded just fine and started running.  I disconnected the ICSP,  unplugged the USB and reconnected and nothing.😮  No lights, no connections, just nothing.  How do you find a problem, without a debugger.  Okay, the ICSP has three wires PGC, PGD and MCLR.  Has to be MCLR or some power up config.  Checked all of that, everything looks good.

I have an LED on a PORT pin.  So I built an infinite while loop that toggles the LED, just in case I needed to look at it on a scope. Put the loop as far in the beginning of the code as I could and it works.  Now I started moving the loop further down the initialization until it failed.  It failed while writing to the EEPROM.

I have base code that gets the serial number, evaluates it and then decides if it is valid (generally fails on all 0xFF, which is a new programmed part).  If it fails, it will save a generic serial number that will validate, but that I know indicates the serial number needs updating.  Also a good test of read/write of wherever the storage is.  I have had problems in the recent past with some newer processors (non Q type) where the solution was to use the library to read/write.  But for my code for this Q processor, I just followed the data sheet example.  When I tried to use the library, the compiler said use the MCC, the library is deprecated.  I examined the MCC generated code and other than using ASM in the lock sequence, there appeared to be no difference, except.....

All of these new processors are 24 bit address for ALL memory.  I noticed the MCC code was intentionally loading all three NVMADR registers.  Where in other processors with 256 bytes of EEPROM, the upper bits really did not matter.  Well in this PIC, they do, if you are not using the debugger.  With the debugger attached, you dont need to load the upper 16 bits, but a normal production start and yes you need to correctly load those 16 bits.  Don't understand it, but that is the way it works.

Now I can get back to updating the Win APP.



Wednesday, April 5, 2023

More MPLAB Fun!

My next step on the Brick Buddy 3 code development was to implement the Bluetooth Interface.  The Brick Buddy 3 uses a RN4871 instead of the RN4020.  I was hoping that the change over was going to be simple, but that does not look like what will happen.

My plan was to use a Mikroe Click Board with an RN4871 on it.  I also have one with an RN4870, which is just bigger version with more I/O pins.  You can see the RN4871 in the picture above on the left. Well the best laid plans, things did not go as planned.  After several failed starts at communications, I finally managed to get Tx/Rx connected.  The RN4871 reset line also worked as advertised, but the system would reboot itself randomly or sometimes continuously.  In the beginning I had just connected the serial port of the RN4871 to FTDI serial to USB converter and used TeraTerm to watch the RN4871 output.  The %REBOOT% would show up every few seconds.  

Searching the Internet this seemed to be an issue with earlier firmware versions.  Also the RN4871 seemed to be sensitive to voltage ripple.  So I did two things to hopefully improve performance.  First I upgraded the firmware to 1.42.  But that did not seem to do much improvement.  So I backed down to 1.41 and there appeared to be improvement.  Next I had a 10uF capacitor across Vcc and GND, right on the click board.  The multiple resets went away and everything seemed to be more stable.  Which one did it, not sure, but it needed the firmware upgrade.  While this picutre is not very good and my soldering was below average on this, you can see the capacitor across the two pins.

With a stable system I started walking through the code I had been using for the RN4020 with modifications for the RN4871.  It would always hang on the first command.  I started stepping through the command and the while loop would not iterate. It always sent the same character to the RN4871.  No matter how I wrote the code, it would not iterate or would iterate by random numbers. I changed the variables to different types, nothing matter.  First I suspected the ISR was changing things.  But that was not the case.  After a day of this, I decided to install every Pack available for MPLAB 6.00. and for the PICKit4.  Most of them installed, then said they do not apply.  But whatever I did, the loop started iterating correctly. I was then able to walk through the command list and could watch the RN4871  respond to each.  Then I used a generic BTLE tool on my phone to see that the RN4871 was correctly advertising all of the characteristics.  

Now it became obvious that a parser was needed.  Different commands result in different ASCII responses.  Thus this is very similar to the old Hayes AT modem.  Looking around I finally found a parser that was generated by the MPLAB Code Configurator, that was a start at this.  It can be found on Github.  This is where I stopped and moved on to ohter things. If time permits I will come back to this and see if I can get something working in a day or two.


Thursday, March 30, 2023

PIC18F46Q71 and I2C


I have been caught up in an I2C nightmare most of the week.  Basically a few years ago Microchip change their implementation of the I2C controller.  Instead of the MSSP which did both SPI and I2C, they now have separate SPI and I2C controllers.  Now it is true that the MSSP probably did not give as much control over the protocol process as one would like.  I am sure the MSSP worked great with all of Microhip's I2C products.  But as with any "specification" it is subject to interpretation, which probably led to a less than ideal mating with other companies products.  The new controller has more settings for SMBUS which is slightly different than I2C in timing and voltage levels.  And it has a more automated mode of working.  It may be better and more flexible. I dont know.  It wasn't that easy to get working in the master state. 

But the PICs I am moving to have this new controller.  There are very few working examples and the firmware that the MCC generator gives you is buggy and hard to understand how to actually implement. It is mostly a cooperative multi-tasking implementation with switch statements and lots of function calls to set one bit in a register.  Now I2C was never straight forward as a protocol, but the MCC code seems to make it more complex than it needs to be.  Sometimes you just want to read an external EEPROM memory and do a simple task.  Not have 10 peripherals running that need to be serviced on a regular basis.

What I found when searching the Internet for working example code was this example on a PIC18F46K42 and a Curiosity HPC.  Since I was working on an HPC this was perfect.  I downloaded the project and started working.  Using my Digilent Analog Discovery 2 as an I2C protocol analyzer, I could see when it worked and when it didn't.   Then I used the driver (.c) and header (.h) files as the starting point for my driver/header files.  Kept modifying these files in the example project until I could read and write the I2C EEPROM I had installed in one of the Click Module sockets on the HPC.  At this point I moved the files back to my project and the PIC18F46Q71 and started testing.  Some minor tweaks to the initialization were needed, but it seemed to work just fine.  

The I2C driver I have running is very basic and runs to completion.  That is it is blocking and will hang the system.  But for now that is OK.  I will need to implement some form of cooperative multi-taksing to get the LP5569 to work, since that is the way it is setup right now.   My only issus is when reading the EEPROM.  The sequence is to write the client address followed by the two bytes that hold the memory address.  this is followed by a restart condition and the PIC resends the client address with read set and starts reading the memory.  Here is the protocol analyzer's view of that sequence.

and just the restart area


The data sheet implies this is OK.  The stop bit is not long enough and all the client IC sees is the restart condition.  We shall see.

 I will leave with this comment form another developer, which was pretty typical of those who posted.

"When you make it hard to use your products, developers will move to other products."

Friday, March 24, 2023

How Not To Code

 

This is going to be a detailed technical post on MPLB X, XC8 PIC C compiler and how not to code a project.  Or to put it simply, how not to be stupid.

The above picture is a Curiosity HPC Development Board that I talked about in this post.  This was to help me get most of the code structure working for the Brick Buddy III as shown here.

The processor on the PCB is a PIC18F26Q71.  Fairly new, but with a very nice of features and lots of program FLASH and RAM.  But it was going to be weeks before I received one from assembly.  Thus the HPC was put into use.  Instead of putting a PIC18F26Q71 in the HPC (it does have a 28 pin socket underneath the 40 pin DIP), I chose to use the 40 pin version, a PIC18F46Q71.  The only difference between the two, besides the physical 28 pins vs 40 pins, is the PIC18F46Q71 has an extra PORT (PORT D).  

The Brick Buddy III code is a derivative of Brick Buddy II and Light Buddy II.  I have not started a project completely from scratch in a long time.  Using common libraries as I explained in this post means that only the main control loop and the hardware initialization is unique, unless there is a new peripheral of some kind.  Once I updated the initialization, I started compiling the code with the PIC18F26Q71 as the processor.  This PIC has the new I2C controller and thus there was a few days of just getting the code to compile.  During the compilation, there were multiple error messages having do with available PIC ports.  Brick Buddy II is a 44 pin device and thus has a PORT D.  All of this had to be changed to accommodate the PIC PORTS available on the PIC18F26Q71.

Once that was done I started trying to see if I could get some of the basic structure working.  This include the serial interface to the PC, the I2C EEPROM that stores configuration and scripts (which would also validate the I2C software driver for the LP5569 IC LED driver).  Finally working on the Bluetooth code for the RN4871.  This BT module is similar to the RN4020, but I am sure there will be some minor road bumps.

Once I had my standard LED heartbeat running, I moved on to the serial interface.  The PCB contains a FTDI USB to UART interface IC.  So I used one of my lab ones to connect the PC to the HPC Development Board with three jumper wires (Rx, Tx & GND).  And nothing worked.

Most PICs have a Peripheral Pin Select (PPS) module.  This allows you to move digital peripheral  features to different pins.  It is basically a large switch matrix.   Some PICs can move the peripherals to any pin while others will restrict a peripheral to a subset of the PORTS.  Thus there is code at initialization that has to be executed to move the peripheral output to the desired pin.  This is shown here

        #if defined(USE_PCB)
            INT2PPS = 0x01;         // assign INT1 to RA0
            INT0PPS = 0x08;         // assign INT0 to RB0
            U1RXPPS = 0x0B;         // assign Rx1 to RB3    --RN4871
            U2RXPPS = 0x0C;         // assign Rx2 to RB4    --Console
            I2C1SCLPPS = 0x13;      // assign SCL1 to RC3        
            I2C1SDAPPS = 0x14;      // assign SDA1 to RC4

            RC3PPS = 0x20;          // assign SCL1 to RC3
            RC4PPS = 0x21;          // assign SDA1 to RC4
            RB2PPS = 0x15;          // assign Tx1 to RB2    --RN4871
            RB5PPS = 0x18;          // assign Tx2 to RB5    --Console
            RC2PPS = 0x0D;          // assign CCP1 to RC2
            RC5PPS = 0x0E;          // assign CCP2 to RC5
            RC6PPS = 0x0F;          // assign PWM1 to RC6
            RC7PPS = 0x11;          // assign PWM2 to RC7
        #elif defined(USE_DEV_BRD)
            INT2PPS = 0x15;         // assign INT1 to RC5
            INT0PPS = 0x0C;         // assign INT0 to RB4
            U1RXPPS = 0x10;         // assign Rx1 to RC0    --RN4871     
            U2RXPPS = 0x0D;         // assign Rx2 to RB5    --Console
            //U2RXPPS = 0x19;         // assign Rx2 to RD1    --Console
            I2C1SCLPPS = 0x13;      // assign SCL1 to RC3        
            I2C1SDAPPS = 0x14;      // assign SDA1 to RC4

            RC3PPS = 0x20;          // assign SCL1 to RC3
            RC4PPS = 0x21;          // assign SDA1 to RC4
            RC1PPS = 0x15;          // assign Tx1 to RC1    --RN4871
            RD0PPS = 0x18;          // assign Tx2 to RD0    --Console
            RC2PPS = 0x0D;          // assign CCP1 to RC2
            RC5PPS = 0x0E;          // assign CCP2 to RC5
            RC6PPS = 0x0F;          // assign PWM1 to RC6
            RC7PPS = 0x11;          // assign PWM2 to RC7
            RD1PPS = 0x00;
        #endif

What this also shows is that I have a conditional compile. One version for the PCB and one for the HPC Development Board.  What I found was that UART2 Rx pin would not work on any of the PORT D pins, even though the data sheet clearly indicated that it good be moved to either PORT B or PORT D.  The UART2 Tx pin worked on any of the PORT D pins I placed it on.  I verified that there was a signal present using my Digilent Analog Discover 2 (which I highly recommend).  Thus I moved the UART2 Rx pin to PORT B and all was good.  I needed to make progress, so I moved on.  Though I did post in the Microchip Support Forum what had happened.

Well someone commented on the post.  When I read the comment, I immediately knew that person had the correct answer and I had fallen again for what I discussed a month ago in this post.  Embarrassment does not even begin to describe how I felt.

Here is the initialization code with the issue

    TRISA = 0xFF;
    TRISB = 0xFF;
    TRISC = 0xFF;
    LATA = 0;
    LATC = 0;
    ANSELA = 0x00;                //all digital
    ANSELB = 0x00;                //all digital
    ANSELC = 0x00;                //all digital
    ADCON0 = 0x00;                //A2D off
    ADCON1 = 0x00;                //+ref is Vdd and -ref is Vss
#if defined (USE_PCB)
    mLED_TRIS = OUTPUT_PIN;       // make it an output
#elif defined(USE_DEV_BRD)
    mLED_B_TRIS = OUTPUT_PIN;     // make it an output
    mLED_Y_TRIS = OUTPUT_PIN;     // make it an output
#endif
    

I had the foresight to place a conditional compile for the heartbeat LED (mLED_B & mLED_Y) to control the TRIS control for the pin.  But if you look directly above that, you will notice there is no mention of either TRISD or ANSELD.

Now TRISx controls whether the PORT pin is an input or an output.  The default is INPUT, but I always like to set them all to inputs and then let the code determine which pins are inputs and which are outputs. ANSELx controls whether the PORT is an analog input pin or a digital I/O pin.  The default is analog input pin, but again I choose to make all port pins digital I/O and then let the code set those pins that will have an analog input..  But this code fragment does not set PORT D to digital I/O and thus all the PORT D pins are analog inputs.

Now the quirk in these PICs is that a digital output (TRISx = 0) will override the analog input selection.  But a digital input will not override the analog input selection.  If you think about this, that only makes sense.  When you want an analog input ( e.g. ADC input) you will set the TRIS register to input and the ANSEL register to input.  The only setup for the processor to know that you want a digital input is the ANSEL register has to be set correctly.  So here is what the code fragment looks like now.

    // Make all digital inputs for now and let init routines set the tris bits that  need to be outputs.
    TRISA = 0xFF;
    TRISB = 0xFF;
    TRISC = 0xFF;
    LATA = 0;
    LATC = 0;
    ANSELA = 0x00;                //all digital
    ANSELB = 0x00;                //all digital
    ANSELC = 0x00;                //all digital
    ADCON0 = 0x00;                //A2D off
    ADCON1 = 0x00;                //+ref is Vdd and -ref is Vss
#if defined (USE_PCB)
    mLED_TRIS = OUTPUT_PIN;       // make it an output
#elif defined(USE_DEV_BRD)
    TRISD = 0xFF;
    LATD = 0x00;
    ANSELD = 0x00;                // all digital
    mLED_B_TRIS = OUTPUT_PIN;     // make it an output
    mLED_Y_TRIS = OUTPUT_PIN;     // make it an output
#endif

 

Live and learn, maybe😕


Monday, March 20, 2023

MPLAB X Issues


I thought I would get a head start on the firmware for Brick Buddy 3 while waiting for the PCBs to arrive.  I would use the Curiosity HPC development board I had originally used in the Solar Shed project.  The HPC is on the right.

This is the only development board I have that would hold a 28 pin PIC.  I decided to just go with a PIC18F46Q71, which is the 40 pin version.  The attractive part is the two Mikroe Click sockets on this board.  One could be the RN4871 Bluetooth module and the other would some generic I2C Click board (I2C EEPROM memory) so that I can work out the I2C driver.  This was also driven by the need to check out the new common libraries I discussed earlier in this post. The Q71 family has the improved full featured standalone I2C module instead of the standard MSSP that has been in PIC18F for a very long time.  The PIC18F Q71 offered great PWM capability, 28 pin SSOP, good amount of memory ( FLASH and RAM) and some other goodies that escape me now.  Oh and I could buy it.  

And the fun begins.  There are now two versions of this Curiosity HPC.  All of the Curiosity boards have built in PICkits.  Well version 1 ( what I have) is based on PICKit3 and the version 2 on PICKit4.  And wouldn't you know it, version 1 of the HPC will not support the PIC18FxxQyy devices.  No biggee, there is a 6 pin ICSP header. I removed R13, R14, R15 which were the resistors on PGC, PGD and MCLR.  These three resistors connect back to the built in debugger.  Removing them isolates the built in debugger hardware.  I soldered on a 6 pin header to the ICSP pads, connect my PICKit4 and I should be good.

Well that was awful naive of me.  First off only the latest versions of MPLAB X will program these chips.  The earlier versions were happy to compile the code, but connect to the PICKit4, not happening.  So I downloaded the latest version MPLAB X  6.05.  It connects, blank tests, reads the memory, but when you program/debug it just hangs at the programming the configuration memory, which is the first memory area it tries to program.

This mess started last week.  I tested another 40 pin dip I had (PIC18F46K40), no issues.  So the connection is good.  So I must have damaged the PIC18F46Q71.  What else could it be.  

I was not smart enough to order two PIC18F46Q71 parts when I ordered the first one.  So another Digi-Key order and wait for arrival.  Side note: USPS delivered in 3 days, 1st class.

I then started again.  And the same result.  Posted in the Microchip Forums, not much help.  After trying all kinds of stuff, I finally went to another computer.  Maybe the computer is corrupted.  But instead of version 6.05, I installed the supposedly buggy 6.00.  And it works.  Went back to the original computer, removed 6.05, installed 6.00 and it works.  For grins, I re-installed 6.05 and it still doesn't work.  So not sure what the definition of "buggy" is anymore.

At this point I claimed victory and will just stick with 6.00 for this one project.  Filed a case and updated the forum with my results. Maybe it will save someone else the hassle. If you have acces to the Microchip forum and want more details, search for "SOLVED : PIC18F46Q71 will not program"

More than I thought to just get a simple development board up and running, but that seems to be always the case.😊