News:

;) This forum is the property of Proton software developers

Main Menu

Transmit Firmware to pic

Started by Pepe, Jan 26, 2022, 02:18 PM

Previous topic - Next topic

Pepe

Is it very complicated to record a program to a 18f26k22 by means of an sd card connected to it?
It occurs to me to read the card at startup and write the pic memory and then transfer the boot vector to the start position of the program.

towlerg

So kinda like a booloader except you do it on every boot?

Why would you want to do this. BTW even the best SD cards are still shit slow (and unreliable)

Pepe

If a kind of bootloader but only once to save the program in the pic without using the pickit programmer.

tumbleweed

It could be done but it'll require having a bootloader that can read an SD card, so if you wanted to stick to a standard format card it might make your bootloader rather large.

I would think it would be simpler (and smaller) to just use a standard serial bootloader.

Pepe

It is so that the customer can update the firmware without depending on the manufacturer of the product.

trastikata

Then you need a bootloader capable of SD card reading. You need to decide how the updates and the Firmware distribution will happen - file system (NTFS or FAT) or serial only - if serial only how you are going to distribute the Firmware etc.

More you need to protect the bootloader sectors from overwriting and the fuse configuration addresses so the user can't brick the device in any circumstance.

top204

#6
It can be done nicely with a PIC microcontroller acting as a bootloader and reading the new program from its own flash memory, or from a seperate SD card formatted with FAT16 or FAT32. To show its general principle, the code below is the bootloader section of a product I created for someone last year, that reads the program and EEPROM data from an SD card and transmits it to a standard bootloader sitting at the top of the slave's memory. The code will not mean a lot to most readers, and it is not much use on its own because libraries are missing etc, but it shows that it can be done with a single 64K, 28-pin, PIC18F microcontroller and the Positron8 compiler. :-) The code below also displayed what it was doing on an ILI9341 colour LCD:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Bootloader Master procedures
' Written for the Positron8 compiler by Les Johnson
'
' Create some constants
'
$define cBlock_WordSize 32                              ' The amount of words that can be written in a single block
$define cErase_WordSize 32                              ' The amount of words erased in a single block
$define cBlock_ByteSize $eval (cBlock_WordSize * 2)     ' The amount of bytes that can be written in a single block
$define cErase_ByteSize $eval (cErase_WordSize * 2)     ' The amount of bytes erased in an single block

$define cEepromSize 1024                                ' Size of EEPROM

$define cIdTypePIC $6E                                  ' The microcontroller type within the slave unit
$define cMax_Flash _code                                ' The amount of flash memory on the device (in bytes)
'
' Create some variables
'
    Dim Global_tResult As Bit
    Dim Global_dSlave_ProgAddress As Dword              ' Holds the address to Program the Flash memory into the slave unit at
    Dim Global_wSlave_EEPROM_Address As Global_dSlave_ProgAddress.Word0    ' Holds the address to Program the EEPROM into the slave unit at

    Dim Global_bCRC_Value      As Byte                  ' Holds the CRC value received from the bootloader's firmware
    Dim Global_wSizeOfProgram  As Word                  ' Holds the amount of data in the Program flash table
    Dim Global_bEE_BytesAmount As Byte                  ' Holds the amount of EEPROM bytes to write

    Dim Global_bFlashBuffer[256] As Byte Heap           ' Holds a block to write Flash to the slave unit
    Dim Global_bEEPROMBuffer[256] As Byte Heap          ' Holds a block to write EEPROM to the slave unit

    Dim wFSR0 As FSR0L.Word
    Dim wFSR1 As FSR1L.Word

$ifndef True
    $define True 1
$endif
$ifndef False
    $define False 0
$endif

'------------------------------------------------------------------------------
' The main programming procedure starts here
' Input     : None
' Output    : Returns false if a problem occurs
' Notes     : Reads from the SD card for the Program to bootload to the slave device
'
Proc Start_Program(), Bit

    Dim SerString As String * 20 Heap                                               ' Holds the serial number read from the unit

Again:
    IntGlobal_Disable()                                                             ' Disable global interrupts while uploading
    Global_Battery_wPrevColour = 0                                                  ' Reset the previous battery line colour so it displays
    Result = True                                                                   ' Default to a true return from the procedure

    LCD_Cls(cUnitTypeNoDisp, cUnitFirmwareNoDisp, False)                            ' Clear the display fully
    PinLow Slave_Reset_Pin                                                          ' Make the MCLR reset pin low so it keeps the slave unit in reset
    DelayMS 512                                                                     ' A delay after resetting the slave
    PinInput Slave_Reset_Pin                                                        ' Make the MCLR pin and input to start the slave unit
    USART1_Baud9600()                                                               ' Place the tester to 9600 Baud so it can communicate with the slave unit
'
' Check the battery voltage before commencing with the bootloading
'
    HLVD_Init()                                                                     ' Initialise the HLVD peripheral for battery voltage checking
    While HLVD_BandGapVoltageStable() = 0: Clrwdt: Wend                             ' Wait for it to become stable
    DelayMS 100                                                                     ' A small delay before testing it

    If HLVD_OutputStatus() = 1 Then                                                 ' Has the HLVP peripheral triggered because of low battery voltage?
        DisplayError(cGeneralError, cErr_LowBattery, "", True)                      ' Yes. So Display an error message with the battery powering the bootloader board
        Result = False                                                              ' Return a false result
        GoTo ProcExit                                                               ' Jump to the section that handles what to do after an error                                                                   ' Exit the procedure
    EndIf
'
' Check if there is an SD card inserted
'
    If SD_Detect_Pin = SD_cNotInserted Then                                         ' Is the SD insterted?
        SD_tInserted = False                                                        ' No. Set the flag
        ILI9341_PenColour(clWhite)                                                  ' Set the pen colour to white
        ILI9341_SetFont(TahomaBold_14)                                              ' Set the font for
        ILI9341_PrintAtCentre(cMessageLine1, "ERROR!")
        ILI9341_PrintAtCentre(cMessageLine2, "The   SD   Card   is   Missing")
        ILI9341_PrintAtCentre(cMessageLine3, "Please   Insert   the   SD   Card")
        Repeat                                                                      ' \
            DelayMS 10                                                              ' |  Create a loop until the SD card is inserted
        Until SD_Detect_Pin = SD_cInserted                                          ' /
        ILI9341_Cls(cBackGroundColour)                                              ' Clear the LCD
        ILI9341_PenColour(clWhite)                                                  ' Set the pen colour to white
        DelayMS 2000                                                                ' A delay before the SD card is initialised
    EndIf
'
' Check if the SD card and FAT can be initialised
'
' Initialise the SD and the FAT
'
    If FAT_Init() <> cErrOK Then                                                    ' Can the FAT be initialised?
        DisplayError(cGeneralError, cErr_SDInitError, "", False)                    ' No. So Display the error message: "Cannot init SD"
        Result = False                                                              ' Return a false result
        GoTo ProcExit                                                               ' Jump to the section that handles what to do after an error
    EndIf
'
' Initiate the bootloader for the firmware required
'
    If Global_bSlaveFirmwareVer = "3" Then                                          ' Is the slave unit running firmware versions 3.0x?
        Global_sFlashFileName = "F3.PRG"                                            ' Yes. So choose the F3.PRG flash data file
        Select Global_bSlaveUnitType                                                ' Check what the slave type is
            Case 1, 2                                                               ' Is the slave unit a type 1 or 2 on a 3.0x firmware unit?
                Global_sEEPROMFileName = "P3.EEP"                                   ' Yes. So set the file for the EEPROM data

            Case 3                                                                  ' Is the slave unit an 3type on a 3.0x firmware unit?
                Global_sEEPROMFileName = "E3.EEP"                                   ' Yes. So set the file for the EEPROM data
        EndSelect

    ElseIf Global_bSlaveFirmwareVer = "4" Then                                      ' Is the slave unit running firmware versions 4.0x?
        Read_Slave_EEPROM(75)                                                       ' Yes. So read address 75 from the slave unit's EEPROM. Into "Global_bEEPROM_Value"
        If Global_bEEPROM_Value = "0" Then                                          ' Is the Light Sensor type value "0"?
            Global_sFlashFileName = "F4L.PRG"                                       ' Yes. So choose the F4L.PRG flash data file because the slave unit is using an LDR as the light sensor
            Global_sEEPROMFileName = "E4L.EEP"                                      ' Use the file E4L.EEP" for the EEPROM data
        Else                                                                        ' Otherwise... The slave unit is using a Photo Diode for the light sensor. So...
            Global_sFlashFileName = "F4.PRG"                                        ' Use the F4.PRG flash data file
            Global_sEEPROMFileName = "E4.EEP"                                       ' Use the file E4.EEP for the EEPROM data
        EndIf
       
    ElseIf Global_bSlaveFirmwareVer = "5" Then                                      ' Is the slave unit running firmware versions 5.0x?
        SerString = Get_Slave_Serial()                                              ' Yes. So read the serial number string from the slave unit
        If SerString[6] = "0" Then                                                  ' Is the Light Sensor used within the slave unit an LDR?
            Global_sFlashFileName = "F5L.PRG"                                       ' Yes. So choose the F5L.PRG flash data file, because this file has the firmwware for LDR use.
            Select Global_bSlaveUnitType                                            ' Check what the slave type is

                Case 1                                                              ' Is the slave unit 1 type on a 5.0x firmware unit?
                    Global_sEEPROMFileName = "S5L.EEP"                              ' Yes. So set the file for the EEPROM data using an LDR light sensor

                Case 2                                                              ' Is the slave unit type on a 5.0x firmware unit?
                    Global_sEEPROMFileName = "P5L.EEP"                              ' Yes. So set the file for the EEPROM data using an LDR light sensor

                Case 3                                                              ' Is the slave unit a 3 type on a 5.0x firmware unit?
                    Global_sEEPROMFileName = "E5L.EEP"                              ' Yes. So set the file for the EEPROM data using an LDR light sensor
            EndSelect
       
        Else                                                                        ' Otherwise... The slave unit's Light Sensor is not an LDR. So...
            Global_sFlashFileName = "F5.PRG"                                        ' Choose the F5.PRG flash data file.
            Select Global_bSlaveUnitType                                            ' Check what the slave type is

                Case 1                                                              ' Is the slave unit a 1 type on a 5.0x firmware unit?
                    Global_sEEPROMFileName = "S5.EEP"                               ' Yes. So set the file for the EEPROM data

                Case 2                                                              ' Is the slave unit a 2 type on a 5.0x firmware unit?
                    Global_sEEPROMFileName = "P5.EEP"                               ' Yes. So set the file for the EEPROM data

                Case 3                                                              ' Is the slave unit a 3 type on a 5.0x firmware unit?
                    Global_sEEPROMFileName = "E5.EEP"                               ' Yes. So set the file for the EEPROM data
            EndSelect
        EndIf
    Else                                                                            ' Otherwise... None of the above are correct. So...
        DisplayError(cGeneralError, cErr_WrongType, "", True)                       ' Display an error message on the bootlaoder's LCD
        Result = False                                                              ' Return a false result
        GoTo ProcExit                                                               ' Exit the procedure
    EndIf
'
' Open and Read the appropriate EEPROM file into its buffer array because it cannot be opened and read after flash memory is written
' Otherwise it is too slow and a serial timeout occurs
'
    'Global_sEEPROMFileName = "S3.EEP"  '<<<<<<<< For Debug
    If Read_EEPROM_File(Global_sEEPROMFileName) = False Then            ' Can the EEPROM file be opened and read?
        Result = False                                                  ' No. So Rreturn a false result
        GoTo ProcExit                                                   ' Exit the procedure
    EndIf
'
' Open the appropriate flash memory file before writing to the slave unit
'
    If File_Open(Global_sFlashFileName) <> cErrOK Then                  ' Can the file be opened?
        DisplayError(cGeneralError, cErr_CannotOpenFile, Global_sFlashFileName, False) ' No. So display an error message on the LCD
        Result = False                                                  ' Return a false result
        GoTo ProcExit                                                   ' Exit the procedure
    EndIf
'
' Change the Baud Rate because the Slave unit's bootloader is running at 19200 Baud, not 9600 Baud
'
    USART1_Baud19200()
    Battery_Check()                                                     ' Check and display the master's battery voltage
    If SearchForBootloader(True) = True Then                            ' Is the bootloader found on the slave unit?
        '
        ' Write the EEPROM to the slave unit using the appropriate EEPROM data file
        '
        If Write_EEPROM() = False Then                                  ' Yes. So did the slave's EEPROM write correctly?
            DisplayError(cGeneralError, cErr_EepromError, "", True)     ' No. So Display an error message when programming EEPROM on the slave unit
            Result = False                                              ' Return a false result
            GoTo ProcExit                                               ' Jump to the section in the procedure when an error occurs
        EndIf
        '
        ' Write the main flash memory to the slave unit using the appropriate flash memory file
        '
        If Write_MainFlash(Global_sFlashFileName) = False Then          ' Yes. So did the main flash block write correctly?
            DisplayError(cGeneralError, cErr_FlashMemError, "", True)   ' No. So Display an error message when programming flash memory on the slave unit                                                                       ' Close the block write loop
            Result = False                                              ' Return a false result
        EndIf
    Else                                                                ' Otherwise... the bootloader was not found on the slave unit. So...
        DisplayError(cGeneralError, cErr_NoBootLoader, "", True)        ' Display an error message on the LCD to indicate no bootloader found on the slave unit
        Result = False                                                  ' Return a false result
    EndIf
'
' Jump here if an error occurs while writing to the slave unit
'
ProcExit:
    Reset_Slave_Unit(False)                                             ' Reset the slave unit
    LCD_TextCls()                                                       ' Clear the tester unit's LCD text area
    PinInput Slave_Reset_Pin                                            ' Make the slave unit's MCLR reset pin high so it resets the slave unit
    USART1_Baud9600()                                                   ' Place the tester back to 9600 Baud so it can communicate with the slave unit

    If Result = True Then
        Block_Cls(0, 206, ILI9341_cWIDTH, 16)                           ' Clear any remainder of the progress bar from the display
        Get_Slave_Firmware_Ver()                                        ' Get the slave unit's new firmware version
        LCD_TextCls()                                                   ' Clear the text section only of the master LCD, leaving the unit type and version at the top

        ILI9341_PrintAtCentre(cMessageLine1, "Finished")
        ILI9341_PrintAtCentre(cMessageLine2, "Uploading")
    EndIf
'
' Wait for a button press
'
    If WaitForButtonPress(False) = cRightButton Then                    ' Is the right hand button pressed?
        GoTo Again                                                      ' Yes. So start the programming again
    EndIf
    LCD_Cls(cUnitTypeNoDisp, cUnitFirmwareNoDisp, False)                ' Clear the display completely
    Mode_TestOrProg(False)                                              ' Display the texts "PROGRAM" or "TEST" on the LCD before leaving the procedure
    Global_Battery_wPrevColour = 0                                      ' Reset the previous battery line colour so it displays
    IntGlobal_Enable()                                                  ' Re-Enable global interrupts
EndProc

'------------------------------------------------------------------------------
' Write a byte to the bootloader via USART1
' Input     : pValue holds the value to write
' Output    : Global_bCRC_Value holds the CRC value calculated from the value written
' Notes     : Updates the CRC value after writing.
'           : Has a small delay after writing the byte
'
$define Slave_WriteByte(pValue)                    '
    HRSOut1 pValue                                 '
    Global_bCRC_Value = Global_bCRC_Value + pValue '
    DelayUS 1024

'------------------------------------------------------------------------------
' Write the main flash memory to the slave unit
' Input     : pFileName holds the filename of the flash memory file to read for programming
' Output    : Returns false if an error occured
' Notes     : None
'
Proc Write_MainFlash(pFileName As String * 20), Bit
    Dim bLine As Byte = 0
    Dim bBytein As Byte
    Dim bBlockIndex As Byte
    Dim wBlock As Word = 0

    Result = True                                                       ' Default to no error while writing
'
' Read the serial number from the file on the SD card
'
    Clear Global_ASCII_Chars                                            ' Clear the string receiving the data into
    Global_ASCII_Chars[0] = File_ReadByte()                             ' Read the first character of the firmware value
    Global_ASCII_Chars[1] = File_ReadByte()                             ' Read the second character of the firmware value
    Global_ASCII_Chars[2] = File_ReadByte()                             ' Read the third character of the firmware value
    bBytein = File_ReadByte()                                           ' Read the CR or LF from the end of the line ($0D or $0A)
    If bBytein = $0D Then                                               ' Is the byte read from the file $0D. i.e. A Carriage Return?
        bBytein = File_ReadByte()                                       ' Yes. So read the LF after the CR from the end of the line ($0A)
    EndIf
    If bBytein <> $0A Then
        DisplayError(cGeneralError, cErr_IncorrectFileType, pFileName, False)   ' Display an error message on the LCD
        Result = False                                                  ' Return a false result
        File_Close()                                                    ' Close the file
        ExitProc                                                        ' Exit the procedure
    EndIf

    Global_FileVersionName = Global_ASCII_Chars#0 + "." + Global_ASCII_Chars#1 + Global_ASCII_Chars#2   ' Build a firmware value with a decimal point from the file's version number
    Global_TempString = "Version   " + Global_FileVersionName
    ILI9341_PrintAtCentre(cMessageLine2, Global_TempString)             ' Display the firmware version that is being uploaded
'
' Read the file containing the flash memory, and bootload the slave unit with it
'
    Clear Global_ASCII_Chars                                            ' Clear the HEX digit storing string before entering the loop
    Global_dSlave_ProgAddress = $000000                                 ' Load the address where to start writing in the slave unit
    While File_tEOF = False                                             ' Read until the file is finished
        bBlockIndex = 0                                                 ' Reset the block storage array's index before entering loop
        Do                                                              ' Create a loop to read the main flash memory data
            Global_bTemp1 = File_ReadByte()                             ' Read a byte from the file
            If Global_bTemp1 = "*" Then                                 ' Is the byte read from the file a "*"?
                File_ReadByte()                                         ' Yes. So this is the end of the line, so read the LF from it ($0A)
                If Write_FlashBlock() = False Then                      ' Did the block Write to the slave unit?
                    DisplayError(cGeneralError, cErr_FlashWriteError, "", False)       ' No. So display an error message on the LCD
                    Result = False                                      ' Return a false result
                    File_Close()                                        ' Close the file
                    ExitProc                                            ' Exit the procedure
                EndIf
                bBlockIndex = 0                                         ' Reset the block storage array's index

                ProgressBar(wBlock)                                     ' Draw a horizontal Gauge on the LCD for the program being programmed
                Inc wBlock                                              ' Increment the flash memory block count

            ElseIf Global_bTemp1 = "#" Then                             ' Is the byte read from the file a "#"?
                File_ReadByte()                                         ' Yes. So this is the end of the line and Flash memory file, so read the LF from it ($0A)
                If Write_FlashBlock() = False Then                      ' Did the block Write to the slave unit?
                    DisplayError(cGeneralError, cErr_FlashWriteError, "", False)       ' No. So display an error message on the LCD
                    Result = False                                      ' Return a false result
                    File_Close()                                        ' Close the file
                    ExitProc                                            ' Exit the procedure
                EndIf
                GoTo LastBlockStart                                     ' Exit the main flash memory reading/writing loop and write the last block to the slave unit

            Else
                Global_ASCII_Chars[0] = Global_bTemp1                   ' Transfer the high ASCII nibble character of the HEX value read from the file while checking
                Global_ASCII_Chars[1] = File_ReadByte()                 ' Read the low ASCII low nibble character of the HEX value from the file
                bBytein = HexToInt(Global_ASCII_Chars)                  ' Convert the HEX string into an integer value
                Global_bFlashBuffer[bBlockIndex] = bBytein              ' Load the converted integer value into the buffer array for later writing
                Inc bBlockIndex                                         ' Increment the index of the array for the next read
            EndIf
        Loop
'
' Write the finishing flash memory block to the slave unit
' This is the block that has the true start address of the slave's Program flash code
'
LastBlockStart:
        Clear Global_ASCII_Chars                                        ' Clear the HEX digit storing string before entering the loop
        Global_dSlave_ProgAddress = $00FEC0                             ' Load the address where to start writing in the slave unit
        bBlockIndex = 0                                                 ' Reset the block storage array's index before entering loop
        Do                                                              ' Create a loop to read the last block flash memory data
            Global_bTemp1 = File_ReadByte()                             ' Read a byte from the file
            If Global_bTemp1 = "@" Then                                 ' Is the byte a "@"?
                File_ReadByte()                                         ' Yes. So this is the end of the line and the end of the file, so read the LF from it ($0A)
                If Write_FlashBlock() = False Then                      ' Did the block Write to the slave unit?
                    DisplayError(cGeneralError, cErr_FlashWriteError, "", False)       ' No. So display an error message on the LCD
                    Result = False                                      ' Return a false result
                    File_Close()                                        ' Close the file
                    ExitProc                                            ' Exit the procedure
                EndIf
                GoTo LastExit                                           ' Exit the outer loop

            Else
                Global_ASCII_Chars[0] = Global_bTemp1                   ' Transfer the high ASCII nibble character of the HEX value read from the file while checking
                Global_ASCII_Chars[1] = File_ReadByte()                 ' Read a low ASCII low nibble character of the HEX value from the file
                bBytein = HexToInt(Global_ASCII_Chars)                  ' Convert the HEX string into an integer value
                Global_bFlashBuffer[bBlockIndex] = bBytein              ' Load the converted integer value into the buffer array for later writing
                Inc bBlockIndex                                         ' Increment the index of the array for the next read
            EndIf
        Loop
    Wend
'
' Jump here when the flash memory is finished being programmed
'
LastExit:
    File_Close()                                                        ' Close the file
EndProc

'------------------------------------------------------------------------------
' Write a block of flash memory data to the slave unit's bootloader
' Input     : Global_dSlave_ProgAddress holds the address to write too in the bootloader slave unit
'           : Array Global_bFlashBuffer holds the bytes to be written to the slave unit
' Output    : Returns true if the block was written correctly, otherwise, returns false
' Notes     : Adds the block size just written to Global_dSlave_ProgAddress for the address of the next block
'
Proc Write_FlashBlock(), Bit
    Dim bBytesIndex As Byte                                             ' Holds the amount of bytes to write to the slave unit
    Dim bResp As Byte                                                   ' Holds the response from the slave bootloader. "C" or "N"
    Dim bAttempts As Byte                                               ' Holds the amount of tries to write the flash memory block to the slave unit

    Result = False                                                      ' Default to a false return from the procedure
    bAttempts = 0
    Repeat                                                              ' Create a loop for multiple tries to write the block of Flash memory
        Global_bCRC_Value = 0                                           ' Clear the CRC value before writing the bytes
        '
        ' Transmit the address and the amount of bytes that are going to be sent to the slave bootloader
        '
        Slave_WriteByte(Global_dSlave_ProgAddress.Byte2)                ' Transmit the upper address to write too in the slave unit
        Slave_WriteByte(Global_dSlave_ProgAddress.Byte1)                ' Transmit the high address to write too in the slave unit
        Slave_WriteByte(Global_dSlave_ProgAddress.Byte0)                ' Transmit the low address to write too in the slave unit
        Slave_WriteByte(cBlock_ByteSize)                                ' Transmit the amount of bytes that are going to be written
        '
        ' Create a loop to transmit the bytes read from the Global_bFlashBuffer array
        '
        For bBytesIndex = 0 To cBlock_ByteSize - 1                      ' Create a loop for the amount of bytes in a flash memory blocl
            Global_ByteOut = Global_bFlashBuffer[bBytesIndex]           ' Read a byte from the array holding the data to write
            Slave_WriteByte(Global_ByteOut)                             ' Send the Flash byte to the bootloader
        Next
        Global_dSlave_ProgAddress = Global_dSlave_ProgAddress + cBlock_ByteSize     ' Add the block size to the address to write too for the next block
        Global_bCRC_Value = 256 - Global_bCRC_Value                     ' Calculate the final CRC value
        Slave_WriteByte(Global_bCRC_Value)                              ' Transmit the CRC value to the slave bootloader
        '
        ' Get a response from the bootloader. Either "N" for the CRC failed, or "C" for a good block written
        '
        bResp = HRSIn1, {1024, TimeOut}                                 ' Receive the bootloader's response, with a timeout
        If bResp = "C" Then                                             ' Was the response a "C" value?
            Result = True                                               ' Yes. So set a true result
            ExitProc                                                    ' Exit the procedure
        Else
            Result = False
        EndIf
TimeOut:
        DelayMS 255                                                     ' Create a delay before trying again
        Inc bAttempts                                                   ' Increment the tries counter
    Until bAttempts >= 5                                                ' Exit the loop when 5 or more tries are attempted
    Result = False                                                      ' Set the procedure's result to false because it should not reach here if the block was written correctly
EndProc

'------------------------------------------------------------------------------
' Write a block of EEPROM data to the slave unit's bootloader
' Input     : Array "Global_bEEPROMBuffer" holds the EEPROM data to write to the slave unit
' Output    : Returns true if the block was written correctly, otherwise, returns false
' Notes     : Attemps to write the block several times before indicating a failure
'
Proc Write_EEPROM(), Bit
    Dim bBlockIndex As Byte                                             ' Holds the amount of EEPROM data bytes to write to the slave unit
    Dim bResp As Global_ByteIn                                          ' Holds the response from the slave bootloader. "C" or "N"
    Dim bAttempts As Byte = 0                                           ' Holds the amount of attempts to program the EEPROM block
    Dim wFSR0 As FSR0L.Word = AddressOf(Global_bEEPROMBuffer)           ' Load FSR0L\H with the address of the array holding the EEPROM data

    Do                                                                  ' Create a loop for the attempts to write the EEPROM data
        '
        ' Create a loop to transmit the bytes to the slave's EEPROM from the array "Global_bEEPROMBuffer"
        '
        For bBlockIndex = 0 To Global_bEE_BytesAmount                   ' Create the loop for the amount of bytes in the EepromBlock flash memory table
            Global_bCRC_Value = 0                                       ' Clear the CRC value before writing the byte
            '
            ' Transmit the EEPROM address and the amount of bytes that are going to be sent in a single packet, which is always 1 byte for the EEPROM
            '
            Slave_WriteByte($40)                                        ' Transmit the value that tells the slave unit we are writing to EEPROM within it
            Slave_WriteByte($00)                                        ' Transmit the high EEPROM address to write too in the slave unit
            Slave_WriteByte(bBlockIndex)                                ' Transmit the low EEPROM address to write too in the slave unit
            Slave_WriteByte($01)                                        ' Transmit the amount of bytes that are going to be written (always 1 for EEPROM)

            Global_ByteIn = POSTINC0                                    ' Read a byte from the Global_bEEPROMBuffer array
            Slave_WriteByte(Global_ByteIn)                              ' Send the Flash byte to the slave's bootloader
            Global_bCRC_Value = 256 - Global_bCRC_Value                 ' Calculate the CRC value
            Slave_WriteByte(Global_bCRC_Value)                          ' Transmit the CRC value to the slave bootloader
            '
            ' Get a response from the bootloader. Either "N" for the CRC failed, or "C" for a good byte written
            '
            bResp = HRSIn1, {2048, TimeOut}                             ' Receive the bootloader's response, with a timeout
            If bResp = "C" Then                                         ' Was the response a "C" value?
                Result = True                                           ' Yes. So set a true result
            Else                                                        ' Otherwise... An incorrect response was received. So...
                Result = False                                          ' Set the procedure's result to false
                Break                                                   ' Exit the For-Next loop
            EndIf
        Next                                                            ' Close the For-Next loop
        If Result = True Then                                           ' Was the result from the EEPROM block write true?
            ExitProc                                                    ' Yes. So exit the procedure
        EndIf
        If bAttempts >= 5 Then                                          ' Has there been multiple attempts to write the EEPROM block?
            DisplayError(cGeneralError, cErr_EepromError, "", True)     ' Yes. So Display an error message when programming EEPROM on the slave unit
            Result = False                                              ' Set the procedure's result to false
            Break                                                       ' Exit the Do-Loop
        EndIf
        Inc bAttempts                                                   ' Increment the attempts to write the data counter
    Loop                                                                ' Clase the attempts loop
    ExitProc                                                            ' Exit the procedure here
'
' Jump here if the response times out when reading the slave's bootloader reply
'
TimeOut:
    Result = False
EndProc

'------------------------------------------------------------------------------
' Reset the slave unit and search for the bootloader's response
' Input     : pDisp true if the "Searching for Bootlaoder" text is to be displayed on the LCD
' Output    : Returns true if the bootloader responds with the correct value
' Notes     : The bootloader's firmware returns the device type value when the value $C1 is sent to it
'           : Then it transmits the value "C"
'           : The firmware tries multiple times to get a response from the bootloader
'
Proc SearchForBootloader(pDisp As Global_tDisp), Bit
    Dim bAttempts As Byte                                               ' Holds the amount of times to transmit to the slave unit
    Dim bType As Byte = 0                                               ' Holds the device type returned from the slave unit
    Dim bResp As Byte = 0                                               ' Holds the value "C" returned from the bootloader firmware

    Result = False                                                      ' Default to a false result
    If pDisp = True Then                                                ' Is the display text required on the LCD?
        LCD_TextCls()                                                   ' Yes. So clear the text section only of the master LCD, leaving the unit type and version at the top
        ILI9341_PrintAtCentre(cMessageLine1, "Searching")
        ILI9341_PrintAtCentre(cMessageLine2, "for")
        ILI9341_PrintAtCentre(cMessageLine3, "Bootloader")
    EndIf
'
' Create a loop to send the start byte to the bootloader
' And get a response
'
    For bAttempts = 19 To 0 Step -1                                     ' Create a loop to transmit/receive to the bootloader X amount of times
        PinLow Slave_Reset_Pin                                          ' \
        DelayMS 1000                                                    ' | Reset the slave unit
        PinInput Slave_Reset_Pin                                        ' |
        DelayMS 10                                                      ' /

        HRSOut1 $C1                                                     ' Transmit the init value to the bootloader's firmware
        bType = HRSIn1, {255, TimeOut}                                  ' Receive the bootloader's device type response, with a timeout
        bResp = HRSIn1, {255, TimeOut}                                  ' Receive the bootloader's standard response of "C", with a timeout
        If bType = cIdTypePIC Then                                      ' Was the device type response from the bootloader correct for the device being written too?
            If bResp = "C" Then                                         ' Was the standard response a "C" value?
                Result = True                                           ' Yes. So set a true result
                If pDisp = True Then                                    ' Is the display text required on the LCD?
                    LCD_TextCls()                                       ' Clear the text section only of the master LCD, leaving the unit type and version at the top
                    ILI9341_PrintAtCentre(cMessageLine1, "Uploading")   ' Display on the LCD that uploading has started
                EndIf
                PinLow Slave_Reset_Pin                                  ' \
                DelayMS 1000                                            ' | Reset the slave unit because the printing on the LCD is too slow and the bootloader times out
                PinInput Slave_Reset_Pin                                ' |
                DelayMS 10                                              ' /
                HRSOut1 $C1                                             ' Transmit the init value to the bootloader's firmware
                bType = HRSIn1, {255, TimeOut}                          ' Receive the bootloader's device type response, with a timeout
                bResp = HRSIn1, {255, TimeOut}                          ' Receive the bootloader's standard response of "C", with a timeout
                Break                                                   ' Exit the loop
            EndIf
        EndIf
TimeOut:
    Next                                                                ' Close the loop
EndProc

'------------------------------------------------------------------------------
' Read the EEPROM file into its buffer array "Global_bEEPROMBuffer"
' Input     : pFileName holds the file name of the appropriate EEPROM data file
' Output    : Array "Global_bEEPROMBuffer" holds the bytes read from the file
' Notes     : None
'
Proc Read_EEPROM_File(pFileName As String * 20), Bit
    Dim bBytein As Byte                                                 ' Holds the byte read from the file
    Dim bBlockIndex As Byte                                             ' Holds the index to the storage array
    Result = True                                                       ' Default to a true result
'
' Open the file containing the EEPROM data
'
    If File_Open(pFileName) <> cErrOK Then                              ' Can the file be opened?
        DisplayError(cGeneralError, cErr_CannotOpenFile, pFileName, False) ' No. So display an error message on the LCD
        Result = False                                                  ' Return a false result
        File_Close()                                                    ' Close the file before exiting the procedure
        DelayMS 4000                                                    ' Keep the error message on the display for a few seconds
        ExitProc                                                        ' Exit the procedure
    EndIf
'
' Read the file containing the EEPROM data, and bootload the slave unit with it
'
    Clear Global_ASCII_Chars                                            ' Clear the HEX digit storing string before entering the loop
    bBlockIndex = 0                                                     ' Reset the block storage array's index before entering loop
    Do                                                                  ' Create a loop to read the main flash memory data
        Global_bTemp1 = File_ReadByte()                                 ' Read a byte from the file
        If Global_bTemp1 = "#" Then                                     ' Is the byte read from the file a "#"?
            File_ReadByte()                                             ' Yes. So this is the end of the line, so read the LF from it ($0A)
            Global_bEE_BytesAmount = bBlockIndex - 1                    ' Store the amount of EEPROM bytes to write
            Break                                                       ' Exit the file reading loop

        Else
            Global_ASCII_Chars[0] = Global_bTemp1                       ' Transfer the high ASCII nibble character of the HEX value read from the file while checking
            Global_ASCII_Chars[1] = File_ReadByte()                     ' Read the low ASCII low nibble character of the HEX value from the file
            bBytein = HexToInt(Global_ASCII_Chars)                      ' Convert the HEX string into an integer value
            Global_bEEPROMBuffer[bBlockIndex] = bBytein                 ' Load the converted integer value into the buffer array for later writing
            Inc bBlockIndex                                             ' Increment the index of the array for the next read
            If bBlockIndex >= Bound(Global_bEEPROMBuffer) Then          ' Has the Global_bEEPROMBuffer array been overloaded?
                Result = False                                          ' Yes. So return a false result
                Break                                                   ' Exit the loop if the array is overloaded
            EndIf
        EndIf

        If File_tEOF = True Then                                        ' Has the end of file been reached prematurely?
            DisplayError(cGeneralError, cErr_IncorrectFileType, pFileName, False) ' Yes. So display an error message on the LCD
            Result = False                                              ' Return a false result
            DelayMS 4000                                                ' Keep the error message on the display for a few seconds
            Break                                                       ' Exit the loop
        EndIf
    Loop
    File_Close()                                                        ' Close the file before exiting the procedure
EndProc

For a bootloader that held the new program and EEPROM in its own flash memory to transmit to the slave device, the data was held in flash memory tables. Connecting the PIC bootloader to the slave device's USART and MCLR pins and pressing a button, resetted the slave and uploaded the data to its bootloader while its RGB LED was yellow, then lit up its RGB LED to green if it succeeded, Red if failed:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Flash memory tables that holds the program and EEPROM data to upload

    Dim Prog_4_0x_Flash As Flash8 = {$80, $EF, $7F, $F0, $6D, $EF, $15, $F0, $7A, $EF, $17, $F0, $80, $0E, $01, $6E, $FE, $0E, $2B, $D9, $01, $0E, $29, $D9, $75, $0E, $0D, $6E, $30, $0E, $16, $EF, $02, $F0, $01, $6A, $01, $8E, $1C, $6E, $1C, $52, $02, $E1, $00, $0E, $01, $D0, $01, $0E, $1C, $5E, $40, $0E, $02, $02, $F3, $50, $40, $0F, $1C, $26, $FE, $0E,
                              '
                              ' Address $000040
                              '
                              $14, $D9, $1C, $50, $12, $D1, $01, $6A, $01, $8E, $1C, $6E, $FE, $0E, $0D, $D9, $1C, $50, $0B, $D1, $06, $6A, $80, $0E, $2C, $6E, $00, $D0, $14, $6A, $15, $6A, $16, $6A, $17, $6A, $08, $9A, $0D, $D9, $D8, $A0, $12, $00, $D3, $0F, $D8, $B4, $08, $8A, $2D, $0F, $C6, $0F, $F7, $E2, $0A, $0F, $F5, $E3, $10, $6E, $0F, $6A,
                              '
                              ' Address $000080
                              '
                              $0E, $6A, $0D, $6A, $0A, $0E, $0C, $6E, $6F, $EC, $02, $F0, $10, $50, $0C, $24, $14, $6E, $0D, $50, $15, $6E, $00, $0E, $D8, $B0, $01, $0E, $15, $26, $0E, $50, $16, $6E, $00, $0E, $D8, $B0, $01, $0E, $16, $26, $0F, $50, $17, $6E, $00, $0E, $D8, $B0, $01, $0E, $17, $26, $06, $06, $07, $E0, $E3, $D8, $D8, $A0, $12, $00,
                              '
                              ' Address $0000C0
                              '
                              $C6, $0F, $02, $E2, $0A, $0F, $DA, $E2, $08, $AA, $0B, $D0, $14, $1E, $15, $1E, $16, $1E, $17, $1E, $14, $2A, $D8, $B4, $15, $2A, $D8, $B4, $16, $2A, $D8, $B4, $17, $2A, $14, $50, $D8, $80, $12, $00, $06, $6A, $14, $6E, $15, $6A, $00, $96, $06, $50, $D8, $B4, $00, $86, $05, $0E, $05, $6E, $27, $0E, $11, $6E, $10, $0E,
                              '
                              ' Address $000100
                              '
                              $0C, $D8, $03, $0E, $11, $6E, $E8, $0E, $08, $D8, $11, $6A, $64, $0E, $05, $D8, $11, $6A, $0A, $0E, $02, $D8, $14, $50, $07, $D0, $10, $6E, $15, $50, $0D, $6E, $14, $50, $0C, $6E, $C5, $D9, $0C, $50, $0C, $6E, $05, $4E, $00, $96, $06, $50, $02, $E0, $05, $5C, $07, $E2, $0C, $50, $D8, $A4, $00, $96, $00, $B6, $02, $D0,
                              '
                              ' Address $000140
                              '
                              $30, $0F, $93, $D0, $12, $00, $00, $96, $06, $50, $03, $E1, $00, $86, $0A, $0E, $06, $6E, $21, $C0, $0F, $F0, $20, $C0, $0E, $F0, $1F, $C0, $0D, $F0, $1E, $C0, $0C, $F0, $05, $6A, $17, $6A, $16, $6A, $15, $6A, $0A, $0E, $14, $6E, $72, $D9, $05, $2A, $05, $50, $06, $5C, $F6, $E1, $14, $50, $D8, $A4, $00, $96, $00, $A6,
                              '
                              ' Address $000180
                              '
                              $02, $D0, $06, $2C, $03, $D0, $14, $50, $30, $0F, $6F, $D8, $06, $2E, $E1, $D7, $12, $00, $05, $6E, $06, $50, $01, $E1, $12, $00, $05, $50, $66, $D8, $06, $06, $F9, $D7, $0F, $01, $81, $6A, $81, $8E, $00, $01, $09, $00, $F5, $50, $02, $E0, $02, $D8, $FB, $D7, $12, $00, $19, $6E, $84, $9A, $84, $98, $89, $9A, $89, $98,
                              '
                              ' Address $0001C0
                              '
                              $88, $9A, $88, $98, $88, $96, $88, $94, $19, $50, $00, $B2, $1E, $D0, $3A, $0E, $0D, $6E, $98, $0E, $2B, $D9, $33, $0E, $18, $6E, $28, $D8, $13, $0E, $0D, $6E, $88, $0E, $24, $D9, $23, $D8, $64, $0E, $20, $D9, $20, $D8, $64, $0E, $1D, $D9, $22, $0E, $18, $6E, $1B, $D8, $28, $0E, $07, $D8, $0C, $0E, $05, $D8, $06, $0E,
                              '
                              ' Address $000200
                              '
                              $03, $D8, $00, $82, $19, $50, $01, $D0, $00, $80, $18, $6E, $00, $A0, $09, $D0, $84, $98, $03, $08, $0A, $E3, $09, $D8, $07, $0E, $0D, $6E, $D0, $0E, $06, $D9, $12, $00, $00, $80, $FE, $08, $16, $E0, $84, $88, $00, $A0, $00, $90, $84, $8A, $83, $8A, $18, $A8, $83, $9A, $83, $88, $18, $AA, $83, $98, $83, $86, $18, $AC,
                              '
                              ' Address $000240
                              '
                              $83, $96, $83, $84, $18, $AE, $83, $94, $84, $9A, $18, $3A, $00, $B0, $EE, $D7, $32, $0E, $EB, $D8, $19, $50, $12, $00, $81, $6A, $81, $8E, $09, $00, $F5, $50, $03, $E0, $CF, $EC, $15, $F0, $FA, $D7, $12, $00, $01, $BE, $A4, $D7, $01, $B4, $CF, $EF, $15, $F0, $01, $A2, $05, $D0, $01, $B0, $03, $D0, $01, $B2, $EE, $6E,
                              '
                              ' Address $000280
                              '
                              $12, $00, $2C, $AE, $03, $D0, $EE, $50, $D8, $80, $12, $00, $2C, $52, $D8, $B4, $9A, $EF, $15, $F0, $00, $88, $00, $A8, $00, $98, $00, $BA, $03, $D0, $00, $8A, $41, $D8, $25, $E2, $08, $0E, $11, $6E, $51, $D8, $10, $36, $11, $2E, $FC, $D7, $00, $A8, $2E, $D8, $57, $D8, $51, $D8, $00, $B8, $19, $D8, $1F, $D8, $10, $50,
                              '
                              ' Address $0002C0
                              '
                              $D8, $90, $12, $00, $00, $88, $00, $A8, $00, $98, $00, $BC, $05, $D0, $FE, $0B, $08, $6E, $00, $8C, $D8, $90, $12, $00, $00, $BE, $05, $D0, $18, $6E, $00, $8E, $21, $D8, $05, $E2, $18, $50, $25, $D8, $02, $E2, $00, $A8, $12, $00, $10, $D8, $39, $D8, $00, $9C, $00, $9E, $00, $9A, $01, $D8, $12, $00, $E2, $68, $02, $C0,
                              '
                              ' Address $000300
                              '
                              $E1, $FF, $E1, $2E, $E1, $74, $E9, $98, $E9, $86, $07, $50, $E7, $12, $09, $D0, $E2, $68, $02, $C0, $E1, $FF, $07, $1C, $E5, $16, $E1, $74, $E1, $98, $E1, $86, $E7, $16, $12, $00, $EB, $DF, $1E, $D8, $F3, $DF, $17, $D8, $08, $50, $00, $BA, $01, $09, $10, $6E, $08, $0E, $11, $6E, $10, $36, $D8, $B0, $DF, $DF, $D8, $A0,
                              '
                              ' Address $000340
                              '
                              $E7, $DF, $10, $D8, $0A, $D8, $11, $2E, $F7, $D7, $D8, $DF, $0B, $D8, $E2, $68, $02, $C0, $E1, $FF, $07, $50, $E7, $14, $FF, $0F, $E2, $68, $03, $C0, $E1, $FF, $04, $1C, $DA, $D7, $E2, $68, $03, $2C, $E1, $6E, $E1, $74, $E1, $98, $E1, $86, $04, $50, $CC, $D7, $80, $6E, $F2, $CF, $F3, $FF, $F2, $9E, $81, $6A, $81, $84,
                              '
                              ' Address $000380
                              '
                              $55, $0E, $82, $6E, $AA, $0E, $82, $6E, $81, $82, $04, $00, $81, $B2, $FE, $D7, $81, $94, $7E, $4A, $7F, $2A, $F3, $BE, $F2, $8E, $81, $8E, $12, $00, $7E, $6E, $81, $6A, $81, $80, $80, $50, $7E, $4A, $7F, $2A, $81, $8E, $12, $00, $7E, $6E, $2E, $6A, $81, $6A, $81, $80, $80, $CF, $05, $F0, $7E, $4A, $7F, $2A, $05, $50,
                              '
                              ' Address $0003C0
                              '
                              $D8, $B4, $12, $00, $EE, $6E, $2E, $3E, $F4, $D7, $12, $00, $60, $88, $0F, $01, $5F, $6F, $60, $8E, $64, $0E, $29, $D8, $60, $80, $04, $00, $60, $B0, $FE, $D7, $64, $CF, $1F, $F0, $63, $50, $1E, $6E, $00, $01, $12, $00, $2B, $50, $2A, $10, $D8, $B4, $2A, $2A, $2B, $34, $2B, $18, $E8, $36, $2B, $3A, $2A, $38, $E8, $46,

' More data here..............................

When I had finished the products, they actually amazed me and the customer as to how well they worked for such a small amount of components, and it showed me that I can still do it after my head injury. :-) The principle was straightforward, but complex to accomplish with a single device and my own FAT16/32 and ILI9341 libraries. I've still got it in me to create complex products from scratch. LOL

Send me an email if you want me to create a similar product for you at standard daily rates.

Pepe

Thanks Les for your answer, if I didn't misunderstand, the example you gave to demonstrate that it can be done is using 2 pics, not just one.

top204

#8
Yes. A PIC microcontroller is used as the bootloading master, and the slave microcontroller is the one that has the small bootloader residing in the top of its flash memory.

A full bootloader that reads its own flash memory or a FAT format from an SD card within the microcontroller itself will take up far too much flash memory, and it cannot overwrite itself or its flash and EEPROM data, so they must stay seperate, which will again, take up a large lump of flash memory. An SD FAT library also takes up quite a bit of flash memory, so the microcontroller will be left with very little program space for a loaded program to operate in.

I did, once, create a bootloader in a device that programmed itself from data held in a SIM card when it was plugged into a socket that was connected to the microcontroller's pins and was running my SIM card reading firmware at the top of flash memory, but that was many years ago, when the PIC 18F devices were easier to write too and had smaller amounts of flash memory.

Pepe

#9
After a lot of work I have been able to make a bootloader to record the pic 18f46k22 through a microsd, I attach the example in proteus, if it is executed with the switch in on it loads the example hex that turns on 2 leds intermittently using interrupt routines , the bootloader loads the program from address $3480 and also accepts the interrupt vectors On_Hardware_Interrupt and On_Low_Interrupt as shown in the example leds.bas.
When the pic is powered with the switch on it reads the sd and when it is off it executes the program that was loaded.

top204

Well done, however, over 13K of flash is a big chunk of it used up for a bootloader?


trastikata

If I may suggest something from my experience:

- Write protect the memory blocks where the bootloader resides, even if it means losing some free space
- Set the PIC fuses in the bootloader and write protect the configuration registers in the bootloader

Therefore start your main program from the next unprotected memory block and don't bother with fuse settings in the main program.

Why I am suggesting this - there's always the possibility that the user disrupts the flashing process or tries to flash something else which may result in bricking the device - i.e. not being able to flash it again through the bootloader and will require ICSP programmer.

If the configuration registers and the blocks, where the bootloader resides, are write protected, there's virtually no way for the user to render the device inoperable.   

Pepe

#12
Bootloader fuses are set to protect the code
but in proteus he does not consider them,
Having a simple way to update firmware for a client just by sending the hex file on an sd justifies the 13k size. if there are more than 50k left for the program.
I attach another example

Pepe

Another example in Proteus for sd with Fat32

SeanG_65

If you dont mind, I'm going to nick a bit of this code, and modifiy it so that IF an CF card is inserted, the code on it is downloaded and written as new code into the PIC (for firmwar updating). Not at that stage yet as I just want to get the two way comms with the RS485 slaves going first. I'm writing a system whereby you can add slaves on, hit RESET on the master and it will automatically assign an address to the new slave (up to 253 slaves on the network).

I'm using an 8 bit address (0 & 255 are reserved) but could EASILY be extended to 16 bits, although the initialisation routine might take a few hours. I'll post code in a new topic when I have something vaguely running.

dionbrewington

My past projects all were microchips updated using a serial bootloader.  It wasn't very practical in the field.  I use a ftdi usb to 3.5mm adapter (TTL-232R-5V-AJ) so it just plugs into a audio jack on the device to flash.  My new projects are all ESP32 chips and they update via OTA through wifi.  They connect to my website where I have the firmware and flash across the network.  Now any updates I make any of those users can easily update with just a few clicks in a web interface.  ESP32 modules are around $3.50.  Microchip needs to lower their prices to compete.  I do still use microchips as secondary chips to the ESP chips for timing sensitive parts.