Showing posts with label SST26. Show all posts
Showing posts with label SST26. Show all posts

Monday, June 14, 2021

Daughter Card for Brick Controller 2

Spent more time on this than I wanted.  At first I thought there was a PCB error, then realized I had swapped the two SPI ports from the proto I built earlier.  This meant having to chase down ANSEL, TRIS and port settings on the PIC32.  Once that was solved, the drive registered with Windows and we were off and running.  One interesting item is any SPI baud rate above about 500KHz has no effect on the time to write to the FLASH memory (SST26).  For now I dont care, as long as it reads fast enough to keep the MP3 decoder pipeline full.

Next was to place the MP3 decoder chip on the daughter card.  This again was chasing down incorrect settings on the PIC32, but it was finally started to respond.  Now I need to connect a headphone jack to the board and see if it is decoding properly.  The PCB design has a class D amplifier on it, I just have not improved my soldering skills enough to try it.


Saturday, August 15, 2020

Refactoring Brick Controller 2

One my tasks I needed to do was to refactor the PIC32 firmware.  When you build the firmware in Harmony, it places  most of the newly generated code in APP.C and APP.H.  This is not very modular, especially if you want to reuse features in a follow on project.  Here is what I did:

  • Moved all of the USB functionality (source and headers) to a separate module.  This contains the Harmony framework state machines for USB Tasks, USB Device Events and USB HID events.  All of the variables are contained in a usbData structure instead of the appData structure.  Finally it also includes generic application level handling of the messages.
  • Created a generic I2C header for use by the different I2C modules
  • Created a module for the LP5569 LED light controller IC routines, state machine and I2C implementation.  This uses the generic I2C header file to create the I2C tasks specific to the LP5569.
  • Created a module for the motor control and control of LED10, since these are all connected to output compare peripherals in the PIC32.  This generates the PWM control for the motors and LED10.
  • Created a module to handle the script execution.  This was not part of the Harmony framework, so it was already on the path as a separate module.
  • Created a module for the RN4020 BT Module.  This includes the routines for the USART port that connects the RN4020 to the PIC32. 
  • Create a module that handles the MP3 state machines and control routines for the VS1053 MP3 decoder chip.  (This is actually a TODO item, since I have not tested the new board yet.)
  • Create a module for the file system that is contained in the SST26 FLASH memory chip that holds the MP3 music file.  (This is actually a TODO item, since I have not tested the new board yet.)

So what does that leave in APP.C.  As you might recall, there is a timer generating interrupts at 100ms, 500ms and 1000ms.  The state machine to handle this in APP.C.  My thinking was this is very specific to the Application, so it should stay in APP.C.  Also APP_Tasks is here, which is the main application state machine.  After initialization, here is the main state

        case APP_STATE_SERVICE_TASKS:
     {
            USBTasks();
            FSTasks();
            MP3Tasks();
            LP5569_Tasks();
            PWMCtrl_Tasks();
            BluetoothTasks();
            NVM_Tasks();
            APP_TIMER_Tasks();
            SCRIPT_Tasks();
            break;
     }


Saturday, June 6, 2020

BC II PCBs have Arrived

Received the Brick Controller II PCBs.  Over the next few days I will be doing the necessary static testing to ensure that 1) I designed it correctly and 2) the manufacturer built it correctly.  Follow the progress here as I test these in conjunction with the MP3/FLASH module. 




Wednesday, June 3, 2020

MP3/FLASH Test Platform (Update 2)



Surprisingly the FLASH portion fired right up and worked.  I am now cleaning up the code.  first step was to correct all the USB descriptors so the Brick Buddy PC software will properly recognize the device.  Since the Brick Controller II will be sold without this module, the firmware had to be modified to only check for the device once and not continually.  Dont need to be wasting PIC32 bandwidth looking for things that are not there.  Other cleanup is needed as I dig into this deeper.  But next I am going to modify the Brick Buddy PC GUI and software to handle the new controller.

Monday, June 1, 2020

MP3/FLASH Test Platform (Update 1)

The PCBs are assembled as shown below.  The MP3 decoder has not arrived yet, thus I will only be testing the FLASH drive for now. 



More later as we progress with the testing.

Sunday, May 31, 2020

MP3/FLASH Test Platform


While I am waiting for the main BCII PCB to come back, I am building a test platform for the MP3/FLASH  add on module.  I had developed the code for this module using the Microchip PIC32MX Curiosity Board, a MikroBus Click MP3 module and a MikroBus Click 64Mb FLASH Module.  There is still more code development and I thought it would be better to use the known Microchip Curisoity board to develop on than the new untried BCII PCB. 


I designed a small carrier PCB that would plug into the two MikroBus slots on the Curiosity board and pickup all the signals. 




Then the completed MP3/FLASH module would plug into the carrier board.  Here is a picture of how that will look.

Now all I have to do is assemble the two boards.  The carrier will be easy.  The MP3/FLASH module will be more challenging.  Plus the MP3 portion is handled by a VS1053B and only AdaFruit had them in stock.They are in NYC, so we will see how long this takes for them to come in.





Friday, May 3, 2019

Brick Buddy 2 Daughter Card

The Mass Storage and MP3 player card is almost done.  It is still missing the speaker connector.  The picture below shows what it looks like.


The connector on the left is a place holder until I find the correct 3D model.  Instead of the socket shown, it should be a pin connector on the bottom side. The blank area on the right is for the speaker connection. It will either be a standard 3.5mm jack or some type of push down connection. There is a concern with the height as I am trying to maintain the same dimensions as the Brick Buddy 1.

Previously, I was deciding about the amplifier.  While I had acquired 250 of MAX9711 Class AB amplifiers for free, I was worried about heat and efficiency with those.  Looking around at other options and in particular Class D amplifiers, I chose the MAX98306E.  It was small, relatively inexpensive and has been used by other Makers in projects. Additionally, I was able to get a small evaluation board to play with.

Nothing much else has changed.  The board is a simple 2 layer PCB and about as small as I can make it and still assemble in my lab.

Wednesday, May 1, 2019

Back At It - The Brick Buddy 2


 As always with life, things happen and I have been distracted by work and family.  I have been slowly working on the Brick Buddy 2 platform.  The layout is now complete as the picture below shows.

You can see the TYPE C connector on the right, the Bluetooth module in the center top and the brick interface on the left.

The Brick Interface has four motor connectors using the same style connector as before.  Above that are the four input connectors, using a similar style connector only smaller.  What is good about this connector style is that pre-built  cables are readily available from Digi-Key.  Above that are the 10 connectors for the LEDs.  The first nine are connected to the LP5569 LED controller and thus will have multiple possibilities in lighting control.  This uses the same connector that BrickStuff is using with their LED product line.

In the center left is the connector for the Mass Storage, MP3 player and amplifier, but we will go into further detail about this later...

Finally I changed the external power connector to the same one as the motor connection, since this breaks out to a Power Functions connector.  It allows the Brick Buddy 2 to receive power from any Lego power source. 




In my last post I talked about design decisons that needed to be made.  Here is what happened since then, I went with two spare pins where both are generic inputs and one of them can be an Interrupt input.  If needed I also still have the two programming pins and the Rx pin in the console port.

The motor control pins were complex.  There are only 5 PWM (Pulse Width Modulated) outputs in this version of the PIC32 microcontroller. You could control the motors with one PWM pin on one side of the motor and a static line on the other side of the motor, but I am worried about reliability.  The pins were chosen so that the PWM outputs can be mapped to either side.  Not sure how responsive this is going to be, but I hope it will work.

Next time I will be describing the brick interface in more detail.

Tuesday, February 26, 2019

HID Problem Solved - For Now

I found the issue keeping the HID interface from working.  Every time you receive a HID report, you need to rearm the read interface, which I knew and thought was implemented.  This also needs to happen at the beginning in initialization.  There were several calls to his in the switch statements, but either the code never passed through these case statements or did so at the wrong time.  I put printf statements in the HID event handler and the USB task case statements so I could watch the startup process.  The only HID report that was happening was Set IDLE and then the interface would hang.  So I added the rearm in that event and it all works now.  The PC program and the PIC32 device exchange messages and the PIC32 device is initialized.  Not sure that is the correct place for it, but that is where it is for now.

I coded the MP3 player portion and ran some tests.  When commanded the, PIC32 loads the file, reads it in and sends it to the VS1053.  When it is done, the file is closed and the USB is reconnected.The player code was hung up trying to stop the VS1053, but for a first run, not bad.  Now I need to verify that VS1053 is initialized correctly and the data is going to the right ports.  Time for the logic analyzer.

Observation:
I have noticed that the demo apps are not consistent in implementation.  I have been through about 5 or 6 of them now as I worked on getting the SPI to work, SST26 FAT, a basic HID and then HID and MSD.  They are good at showing functionality, may not be as good at robust production code.  And when you combine two different apps to get combination functionality, you can run into some quirks.

Thursday, February 14, 2019

Basic Brick Controller

Last night I integrated the HID device and my basic packet dispatcher routines.  My basic software structure is as HID packets come in, they are loaded into processing queue.  The HID packet size is set to 64, but in my protocol, the packet size is limited to 20.  (Does not apply to text strings coming back from the Brick Controller.)  These are just control packets except for when a script is downloaded, but that is a maximum of 256 bytes.  Then serial queue is processed and the commands are executed.  All of this seems to work now.

Anywho, the development board connected to the PC, the Brick Buddy PC software recognized the device and started downloading configuration data from the Brick Controller.  At the same time the MSD SPI Flash drive connected and was available for use.  So I have basic HID/Brick Controller functionality and a USB Mass Storage Device.

My next task is to see if I can get the VS1053 MP3 player to work.

Tuesday, February 12, 2019

Working USB Mass Storage Device on SST26

I have a working example of the USB MSD on SST26 SPI Flash.  It is right at 8MB.  I have done read and write testing, while it is a little slow (SPI clock is 200KHz) it is completely functional.  Next step is see if I can raise the SPI clock speed on the PIC32MX470 Curiosity board.  While I do this I am also working on implementing the HID functionality.  Once I have HID functionality, I should be able to implement the current Brick Controller functionality on the Curiosity board.

Here is a more of detailed list of what I changed in the SST25 driver to make it work with SST26 flash.  A zip file with the changes is located here, drv_sst25.zip.  GoDaddy, who is the website host, changes the file name to some random number string to make it unique.  Rename to the link name, will make it easier to track the file.

You should also diff this with the framework one to see if I changed anything else and forgot about it.  More than likely that happened.   I have not included the .h file,  drv_sst25_local.h  that was modified either.  There were additions to the states and commands opcodes.  The big change that caused major havoc for days was cmdParamsLen in the DRV_SST25_OBJ structure.  It was cast as a byte and with 4 byte write commands (command plus 3 address bytes) and 256 byte page writes, it was rolling over to just 4 commands bytes and thus nothing happened.  I have changed this to uint32_t.  Again diff the one in the zip file with the framework one.

1.  I changed this table to include the Flash Type SST25 or SST26, as determined from the JEDEC ID read.

/***********************************************************************************************************/
/* Table mapping the supported Flash ID's to their sizes. All parts must support the JEDEC-ID Read command
   The SST25VF010A is included for backwards compatibility reasons, but is not supported since
   the 25VF010A flash part does not support the JEDEC-ID Read command.  Thus there is no way to read
   ID the part. */
/***********************************************************************************************************/
const uint32_t gSstFlashIdSizeTable [DRV_SST25_NUM_DEVICE_SUPPORTED][3] = {
    {0x25, 0x49, 0x020000}, /* SST25VF010A - 1 MBit */
    {0x25, 0x8C, 0x040000}, /* SST25VF020B - 2 MBit */
    {0x25, 0x8D, 0x080000}, /* SST25VF040B - 4 MBit */
    {0x25, 0x8E, 0x100000}, /* SST25VF080B - 8 MBit */
    {0x25, 0x41, 0x200000}, /* SST25VF016B - 16 MBit */
    {0x25, 0x4B, 0x800000}, /* SST25VF064C - 64 MBit */
   
    {0x26, 0x41, 0x200000}, /* SST26VF016B    - 16 MBit */
    {0x26, 0x42, 0x400000}, /* SST26VF032B/BA - 32 MBit */
    {0x26, 0x43, 0x800000}  /* SST26VF064b/BA - 64 MBit */
};

2.  I changed the GetFlashSize function to look at the flash type first. The JEDEC ID read function loads all three bytes of the JEDEC ID into the FlashID variable of the DRV_SST25_OBJ.  The GetGeometry function then sets a Boolean in this object to indicate SST26 or SST25.  That variable is passed to this function which reads the table above to get the size of the flash. 

/* This function returns the flash size in bytes for the specified deviceId. A
 * zero is returned if the device id is not supported. */
static uint32_t DRV_SST25_GetFlashSize
(
    uint8_t deviceId,
    bool isSST26Device
)
{
    uint8_t i, beginIndex,endIndex;

    if (isSST26Device == true)
    {
        beginIndex = DRV_SST25_NUM_DEVICE_SUPPORTED - SST26_DEVICE_COUNT;
        endIndex = DRV_SST25_NUM_DEVICE_SUPPORTED;
    }
    else
    {
        beginIndex = 0;
        endIndex = SST25_DEVICE_COUNT;
    }
    for (i = beginIndex; i < endIndex; i++)
    {
        if (deviceId == gSstFlashIdSizeTable[i][1])
        {
            return gSstFlashIdSizeTable[i][2];
        }
    }

    return 0;
}




3.  This change is one of the bigger ones.  Right now it rejects anything that is not a MicroChip FLASH.  Then it checks for SST26 or SST25 and stores this in the DRV_SST25_OBJ boolean isSST26.  Then it checks the table for the flash size.  The next sections are switch statements that populate the geometry table based on the Flash found.  I did a case statement for each flash device so there would be no question of the parameters used.  This also provides for future expansion.  The remaining code is unchanged.  For now I left in the old code,commented out.

/* This function updates the driver object's geometry information for the flash
 * device. */
static bool DRV_SST25_UpdateGeometry
(
    DRV_SST25_OBJ *dObj,
    uint8_t deviceId
)
{
    uint32_t flashSize;
   
    if (dObj->flashId[0] != 0xBF)
    {
        return false;  // chip is not a microchip SST
    }
    dObj->isSST26 = (dObj->flashId[1] == 0x26);  // is this a SST26 type device
    deviceId = dObj->flashId[2];
    flashSize = DRV_SST25_GetFlashSize (deviceId, dObj->isSST26);  // get flash size
    if (flashSize == 0)
    {
        return false;  // chip was not in table
    }

    /* Read block size and number of blocks */
    /* All Flash memories are 1 byte in read block size */
    dObj->mediaGeometryTable[0].blockSize = 1;
    dObj->mediaGeometryTable[0].numBlocks = flashSize;

    /* Build switch statements with what each flash device needs for writing */
    if (dObj->isSST26)
    {
        dObj->flashFunctions.unlock = DRV_SST26_UnlockFlash;
        switch (deviceId)
        {
            case 0x41:  // SST26VF016B
            {
                dObj->mediaGeometryTable[1].blockSize = DRV_SST25_PAGE_SIZE;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 8;
                dObj->flashFunctions.write = DRV_SST25_WritePageProgram;
                dObj->opCodes.write = DRV_SST25_CMD_PAGE_PROGRAM;
                break;
            }
            case 0x42:  // SST26VF032B
            {
                dObj->mediaGeometryTable[1].blockSize = DRV_SST25_PAGE_SIZE;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 8;
                dObj->flashFunctions.write = DRV_SST25_WritePageProgram;
                dObj->opCodes.write = DRV_SST25_CMD_PAGE_PROGRAM;
                break;
            }
            case 0x43:  // SST26VF064B
            {
                dObj->mediaGeometryTable[1].blockSize = DRV_SST25_PAGE_SIZE;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 8;
                dObj->flashFunctions.write = DRV_SST25_WritePageProgram;
                dObj->opCodes.write = DRV_SST25_CMD_PAGE_PROGRAM;
                break;
            }
            default:
                break;
        }
    }
    else // flash part is SST25
    {
        dObj->flashFunctions.unlock = DRV_SST25_UnlockFlash;
        switch (deviceId)
        {
            case 0x8C:  // SST25VF020B
            {
                dObj->mediaGeometryTable[1].blockSize = 2;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 1;
                dObj->flashFunctions.write = DRV_SST25_WriteAutoAddressIncrement;
                dObj->opCodes.write = DRV_SST25_CMD_AAI_PROGRAM;
                break;
            }
            case 0x8D:  // SST25VF040B
            {
                dObj->mediaGeometryTable[1].blockSize = 2;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 1;
                dObj->flashFunctions.write = DRV_SST25_WriteAutoAddressIncrement;
                dObj->opCodes.write = DRV_SST25_CMD_AAI_PROGRAM;
                break;
            }
            case 0x8E:  // SST25VF080B
            {
                dObj->mediaGeometryTable[1].blockSize = 2;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 1;
                dObj->flashFunctions.write = DRV_SST25_WriteAutoAddressIncrement;
                dObj->opCodes.write = DRV_SST25_CMD_AAI_PROGRAM;
                break;
            }
            case 0x41:  // SST25VF016B
            {
                dObj->mediaGeometryTable[1].blockSize = 2;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 1;
                dObj->flashFunctions.write = DRV_SST25_WriteAutoAddressIncrement;
                dObj->opCodes.write = DRV_SST25_CMD_AAI_PROGRAM;
                break;
            }
            case 0x4B:  // SST25VF064C
            {
                dObj->mediaGeometryTable[1].blockSize = DRV_SST25_PAGE_SIZE;
                dObj->mediaGeometryTable[1].numBlocks = flashSize >> 8;
                dObj->flashFunctions.write = DRV_SST25_WritePageProgram;
                dObj->opCodes.write = DRV_SST25_CMD_PAGE_PROGRAM;
                break;
            }
            default:
                break;
        }
    }

//    if (deviceId == 0x4B)
//    {
//        /* SST25VF064C */
//        /* Write block size and number of blocks */
//        dObj->mediaGeometryTable[1].blockSize = DRV_SST25_PAGE_SIZE;
//        dObj->mediaGeometryTable[1].numBlocks = flashSize >> 8;
//        dObj->flashFunctions.write = DRV_SST25_WritePageProgram;
//    }
//    else
//    {
//        /* Write block size and number of blocks */
//        dObj->mediaGeometryTable[1].blockSize = 2;
//        dObj->mediaGeometryTable[1].numBlocks = flashSize >> 1;
//
//        dObj->flashFunctions.write = DRV_SST25_WriteAutoAddressIncrement;
//        if (deviceId == 0x49)
//        {
//            /* SST25VF010A */
//            dObj->opCodes.write = DRV_SST25_CMD_AAI_PROGRAM1;
//        }
//        else
//        {
//            dObj->opCodes.write = DRV_SST25_CMD_AAI_PROGRAM;
//        }
//    }

    /* Erase block size and number of blocks */
    dObj->mediaGeometryTable[2].blockSize = DRV_SST25_ERASE_SECTOR_SIZE;
    dObj->mediaGeometryTable[2].numBlocks = flashSize >> 12;

    /* Update the Media Geometry Main Structure */
    dObj->mediaGeometryObj.mediaProperty = (SYS_FS_MEDIA_READ_IS_BLOCKING | SYS_FS_MEDIA_WRITE_IS_BLOCKING),

    /* Number of read, write and erase entries in the table */
    dObj->mediaGeometryObj.numReadRegions = 1,
    dObj->mediaGeometryObj.numWriteRegions = 1,
    dObj->mediaGeometryObj.numEraseRegions = 1,
    dObj->mediaGeometryObj.geometryTable = (SYS_FS_MEDIA_REGION_GEOMETRY *)&dObj->mediaGeometryTable;

    return true;
}

NOTE: From the above three changes it should be easy to add any flash to the table by adjust the size the of the table.  Then the GetGeometry function switch/case statements would be modified to accommodate the discovered flash. 

4.  Finally are the case statements that control the state machine. 

This function

static DRV_SPI_BUFFER_EVENT DRV_SST25_ReadFlashId
 

I changed the size of the read to 3 to conform to the JEDEC ID read.  I also changed the write to 4 just so I could see the ID come back on the logic analyzer.  It is not necessary, but it is a nice debug tool.

This function

static DRV_SPI_BUFFER_EVENT DRV_SST25_UnlockFlash

I did not change.  I had no way to check it, but it should still work with SST25 Flash.  It is selected when the state machine determines it is SST25.

This function I added and is selected when the state machine determines it is SST26

static DRV_SPI_BUFFER_EVENT DRV_SST26_UnlockFlash
(
    void *driverObj
)
{
    DRV_SPI_BUFFER_EVENT event = DRV_SPI_BUFFER_EVENT_ERROR;
    DRV_SST25_OBJ *dObj = (DRV_SST25_OBJ *)driverObj;

    switch (dObj->subState)
    {
        case DRV_SST26_WREN_CMD_SQIORST:
            {
                dObj->cmdParams[0] = dObj->opCodes.writeEnable;
                dObj->disableCs = true;
                DRV_SPI_BufferAddWrite2(dObj->spiDriverHandle, &dObj->cmdParams[0], 1, 0, dObj, &dObj->spiBufferHandle);

                if (dObj->spiBufferHandle != DRV_SPI_BUFFER_HANDLE_INVALID)
                {
                    dObj->subState = DRV_SST26_WREN_STATUS_CHECK_SQIORST;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;
                }
                else
                {
                    /* Failed to queue the write transfer request. */
                    break;
                }
            }

        case DRV_SST26_WREN_STATUS_CHECK_SQIORST:
            {
                event = DRV_SPI_BufferStatus(dObj->spiBufferHandle);
                if (event == DRV_SPI_BUFFER_EVENT_COMPLETE)
                {
                    dObj->subState = DRV_SST26_SEND_CMD_SQIORST;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;                   
                }
                else if (event == DRV_SPI_BUFFER_EVENT_ERROR)
                    {
                        /* Error will be handled in the caller function. */
                    }
                    else
                    {
                        /* Continue to remain in the same state. */
                        event = DRV_SPI_BUFFER_EVENT_PENDING;
                        break;
                    }
            }

        case DRV_SST26_SEND_CMD_SQIORST:
            {
                dObj->cmdParams[0] = dObj->opCodes.sqioReset;
                dObj->disableCs = true;
                DRV_SPI_BufferAddWrite2(dObj->spiDriverHandle, &dObj->cmdParams[0], 1, 0, dObj, &dObj->spiBufferHandle);
                if (dObj->spiBufferHandle != DRV_SPI_BUFFER_HANDLE_INVALID)
                {
                    dObj->subState = DRV_SST26_CMD_STATUS_CHECK_SQIORST;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;
                }
                else
                {
                    /* Failed to queue the write transfer request. */
                    break;
                }
            }

        case DRV_SST26_CMD_STATUS_CHECK_SQIORST:
            {
                event = DRV_SPI_BufferStatus(dObj->spiBufferHandle);
                if (event == DRV_SPI_BUFFER_EVENT_COMPLETE)
                {
                    dObj->subState = DRV_SST26_WREN_CMD_UNLOCK;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;                   
                }
                else if (event == DRV_SPI_BUFFER_EVENT_ERROR)
                    {
                        /* Error will be handled in the caller function. */
                    }
                    else
                    {
                        /* Continue to remain in the same state. */
                        event = DRV_SPI_BUFFER_EVENT_PENDING;
                        break;
                    }
            }
       
        case DRV_SST26_WREN_CMD_UNLOCK:
            {
                dObj->cmdParams[0] = dObj->opCodes.writeEnable;
                dObj->disableCs = true;
                DRV_SPI_BufferAddWrite2(dObj->spiDriverHandle, &dObj->cmdParams[0], 1, 0, dObj, &dObj->spiBufferHandle);

                if (dObj->spiBufferHandle != DRV_SPI_BUFFER_HANDLE_INVALID)
                {
                    dObj->subState = DRV_SST26_WREN_STATUS_CHECK_UNLOCK;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;
                }
                else
                {
                    /* Failed to queue the write transfer request. */
                    break;
                }
            }

        case DRV_SST26_WREN_STATUS_CHECK_UNLOCK:
            {
                event = DRV_SPI_BufferStatus(dObj->spiBufferHandle);
                if (event == DRV_SPI_BUFFER_EVENT_COMPLETE)
                {
                    dObj->subState = DRV_SST26_SEND_CMD_UNLOCK;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;                   
                }
                else if (event == DRV_SPI_BUFFER_EVENT_ERROR)
                    {
                        /* Error will be handled in the caller function. */
                    }
                    else
                    {
                        /* Continue to remain in the same state. */
                        event = DRV_SPI_BUFFER_EVENT_PENDING;
                        break;
                    }
            }

        case DRV_SST26_SEND_CMD_UNLOCK:
            {
                dObj->cmdParams[0] = dObj->opCodes.globalUnlock;
                dObj->disableCs = true;
                DRV_SPI_BufferAddWrite2(dObj->spiDriverHandle, &dObj->cmdParams[0], 1, 0, dObj, &dObj->spiBufferHandle);
                if (dObj->spiBufferHandle != DRV_SPI_BUFFER_HANDLE_INVALID)
                {
                    dObj->subState = DRV_SST26_CMD_STATUS_CHECK_UNLOCK;  // and fall through
                    event = DRV_SPI_BUFFER_EVENT_PENDING;
                }
                else
                {
                    /* Failed to queue the write transfer request. */
                    break;
                }
            }

        case DRV_SST26_CMD_STATUS_CHECK_UNLOCK:
            {
                event = DRV_SPI_BufferStatus(dObj->spiBufferHandle);
                break;
            }
    }

    return event;
}



So what this does differently than the SST25 unlock function.  First it executes a SQIO Reset, ensuring that the device is in SPI mode and not SQIO mode.  Then it does a Global Unlock command.  Each of these is preceded by a write enable command.

Finally this function starts it off 

void DRV_SST25_Tasks

This opens the SPI driver, then reads the flash to determine if it is SST25 or SST26.  The UpdateGeometry function picks the correct unlock sequence and this is then executed.  Then it follows the normal state machine from then on.


Hoepfully this will make it easier for others to follow how the modifications were made.  Again I did not test the SST25 portion, so I may have done something to break this without knowing.  If you find it pass it along and I will update this section.









Tuesday, February 5, 2019

Moving on to USB Device MSD

I started the next phase of design implementing the USB device mass storage device.  This went unusually fast, especially as compared to the last few weeks.  My first attempt enumerated the drive on my PC, but the media failed to mount.  I went back to my FAT Test project just to make sure nothing else changed and that works just fine.

Next step is to integrate the console feature so I can send debug messages out of the serial port to the PC.  Also have a strange event in that once the PC enumerated the drive the starter kit onboard debugger disconnects.   A web search shows this can happen for several reasons, one being wrong configuration descriptors.  Not critical yet, but something to keep an eye on.

Monday, February 4, 2019

I have a working FAT

Well it has been 3 weeks of work on and off to get here.  But I finally have a working file allocation table using a SST26 Flash.  I have made some big changes to the driver so that it will continue to work with both SST25 and SST26 Flash.  Unfortunately I have no way right now to test it with SST25.

Things I changed:
1. Updated the array of supported parts to include all of the SST26 parts
2. Updated the geometry function to be expandable to just about any flash IC by using a large switch statement.  Probably is a better way to do this, but at the time this was easiest.
3.  Changed the flash detect to first find the JEDEC ID and then populate all of the needed functions.  This change eliminated all of the older SST25 parts that did not support the JEDEC ID command.
4.  Separate unlock processes for SST25 and SST26 devices.
5.  Finally had to change the type of one variable, since the SST26 can program in page size.  An 8bit unsigned int was not going to work.

There are other items that were changed and it is best if you do a diff on the original files and the ones I eventually post, just so you know waht was changed.

What I have working is the SST25FAT example.  Not the best test of the driver changes.  Next I am going to integrate the USB MSD drivers so that I can test the drive with a PC.  That way I can write a PC program to read and write the drive with various size files to verify that it works.  Once I know that it is working I will post the firmware here, probably  will be a link back to the website.

More to come!