How can I write binary file onto external flash received from usb

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How can I write binary file onto external flash received from usb

4,144 Views
priyankb
Contributor III

Hi,

I am using lpc4088 custom board with LPCOpen and aim is to use USB CDC to get binary/hex/s19 file from VCOM and send it to external Microchip flash(16 bit) using EMC.

I am trying to read a chunk(64/128/1024) of data from USB and write it to flash. When I read a whole file (say 1KB) and then write to flash, it works.

The write to flash hangs if I try to read 64/128/1024 bytes(multiple chunks of data) and write it to flash in a loop until whole file is written. I don't understand why looping is not working.

Any help will be appreciated.

Thank you.

Priyank.

Labels (5)
19 Replies

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
According to your statement, I get that the writing flash operation can be done well if receiving the complete data via the CDC USB, however, it will encounter some troubles in writing flash operation when just receiving partial data, is it right?
I was wondering if you can share the simple code and introduce the testing process in details, as I'd like to replicate this phenomenon and it can help me to figure it out.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,082 Views
priyankb
Contributor III

Thank you jeremyzhou

I understand what you are saying, but in order to send a big executable file(~1MB) there is no other way. Currently I am trying to move it to external SRAM and then to Flash. But I don't think it is a very efficient way of doing it.

Here is my code,

 (usbd_lib_cdc project in LPCOpen as a base for this)

typedef union Generic_Val {
    uint8_t byte[1024];
    uint32_t bit_32[256];
}Generic_val;

Generic_val Value;

 

while (1)

{
        /* Check if host has connected and opened the VCOM port */
        if ((vcom_connected() != 0) && (prompt == 0))

        {
            vcom_write((uint8_t *)"Hello World!!\r\n", 15);
            prompt = 1;
        }
        /* If VCOM port is opened echo whatever we receive back to host. */
        if (prompt)

        {
            rdCnt = vcom_bread(&Value.byte[j], 1024);

       }

        j += rdCnt;

        if(j >= 1023)
        {
            for(i=0; i<256; i++)
                DEBUGOUT("0x%08xh\r\n", Value.bit_32[i]);


            WriteFlash(addr, (uint16_t*)Value.bit_32, 1024);
        }

}

The above code is the one that works fine. But when I run it in a loop it hangs.

Here is the changes to perform loops,

        if(j >= 1023)
        {
            for(i=0; i<256; i++)
                DEBUGOUT("0x%08xh\r\n", Value.bit_32[i]);


            WriteFlash(addr, (uint16_t*)Value.bit_32, 1024);

            addr += 1024;

            j = 0;
        }

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
Thanks for your reply.
Whether you can show me what the exact place the code will be stuck in when you debug it, as I'd like to know the more details.
And it'd be better if you can share a compile-able demo, then I review the code on my site.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,082 Views
priyankb
Contributor III

Hi jeremyzhou‌,

Thanks for the reply.

Every time the code hangs in the if(j>=1023) part.

Here is my basic demo code. The Flash is on CS3. Timings are same as that of norflash_prog project in LPCopen.

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
There's something wrong with the demo after compiling it.
According to the code, it receives the 1 kb as a unit data, then writes this data to Nor flash, is it correct?
I'd like to try the following code.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

        if(j == 1024)
        {
            for(i=0; i<256; i++)
                DEBUGOUT("0x%08xh\r\n", Value.bit_32[i]);


            WriteFlash(addr, (uint16_t*)Value.bit_32, 1024);

            addr += 1024;

            j = 0;
        }‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos

3,082 Views
priyankb
Contributor III

Hi jeremyzhou‌,

Thanks for the reply.

I have tried every possible combination. Also tried the one you referred but with same result.

The screenshots,

1) 1.png shows it works if buffer is of 512 byte and 512 byte of file is sent via USB.

2) untitled.png shows when 1 KB file is send to a buffer of 512 byte in a loop.

I will be trying to use USB interrupt now to see if that works.

Do you have any code for reference. That would be helpful.

Thanks

Priyank.

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
Thanks for the reply, it gives an insight into this phenomenon, it may be caused by the RealTerm tool, so I'd highly recommend you to analyze the USB transaction via the USB protocol tool and I think it will give you more detailed information about this issue.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,

Thanks for your reply.

1) Now the question arise that is it possible to jump from bootloader(present in internal flash) to my application(present in external flash at 0x9C000000).

-- Yes, it's possible.

2) Do I need to change vector table address here to put it onto external flash

-- Yes, you need do.

Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

3,082 Views
priyankb
Contributor III

Hi jeremyzhou‌,

As you suggested, I have made some changes in my code & configuration but unable to successfully jump to user application.

During debug I found that SP, PC locations are correct but in disassembly window continuously get "failed to execute mi command data-disassemble" error.jump_debug.pngjump1.png

I don't understand the problem. Could you point out the changes need to execute jump from internal flash to external flash.

Thank you.

Priyank.

0 Kudos

3,082 Views
converse
Senior Contributor V

You can see that in your 2nd screenshot, the registers are all garbage - the PC is 0x6a9f3574, which is why you get the disassembly errors.

Have you (assembly) single stepped to see at which point it goes wrong?

What is the code that is setting up the stack and PC?

In your 1st screenshot, the PC is already at 0x9c000188, so it looks like it has jumped to your code, with the SP set to 0x10010000, so what is on the stack at this point?

My guesses are that

a. your (external flash) code is returning, but the stack is garbage

b. an interrupt has fired and either the vector table is not setup correctly, or the MSP/PSP is wrong

0 Kudos

3,082 Views
priyankb
Contributor III

The 2nd screenshot is the one which occur when I try to jump to location 0x9C000189 & the PC jumps to the location stored in that address(0x9c000189) which does not happen when jump to 0x9c000188.

In normal condition the bootloader application continuously resets & user app never gets executed.

Stack points to RAM location 0x10010000 which is same as bootloader.

This is my boot jump code(one of many i tried).

void boot_jump(uint32_t addr)
{
     __asm volatile("LDR R1, [R0]");

     __asm volatile("LDR SP, [R0]");
     __asm volatile("LDR PC, [R0, #4]\n");

     delayMs(5);
}

void Execute_User_Code(void)
{
     Chip_SetupIrcClocking();
     __disable_irq();

     //Clear interrupts
     NVIC->ICPR[0] = 0xFFFFFFFF;
     NVIC->ICPR[1] = 0x0000001F;

     SCB->VTOR =  APP_ADDR & 0xFFFFFF80;

     boot_jump(APP_ADDR);
}

Now my main concern is about vector table mapping. It is seen in .map file that it is present in external flash & I need to copy it to RAM. But in ResetISR() I cannot access external flash not until SystemInit() where EMC initializes.

Any suggestions to solve this problem would be very helpful.

Thank you.

Priyank.

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
Thanks for your reply.
The application code is independent with bootloader, definitely,of course, it's impossible to debug when debugging the bootloader code.
About application code, you should be careful with clock initialization, as EMC maybe inactive when clock configuration changes, please beware of it.
Considering the performance and implementation difficulty, in my opinion, on-chip is used to store code even only has the partial code, versus the external flash is used to store the data, it's a suggestion and maybe you can give a try.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,082 Views
priyankb
Contributor III

Hi jeremyzhou‌,

I was able to successfully jump from bootloader to user application(external flash) but my USB interrupt(endpoint) is not working. I have used the same USB in bootloader but it is unable to communicate. Although it gets enumerated which means USB interrupt works but EP does not. I have tried to reset USB as well as EPs but didn't help. I also tried changing EP no but problem still persist. Tried changing VTOR location to RAM with no success. Also tried to change USB stack memory address but nothing worked. Used same initialization as bootloader so code is tested & works.

Any idea how to solve this problem.

Thanks.

Priyank

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
Firstly, congratulation to jumping operation works.
After jumping to the external flash from the bootloader, the application has been executed well until to enumeration complete, as it's unable to respond to the transaction token, likes IN or OUT token, is it right?
In further, I'd like to know whether this application works well or not when it locates in the internal flash, and I was wondering if you can share the USB transaction communication, as it can help us to figure the issue out.

Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

3,082 Views
priyankb
Contributor III

Hi jeremyzhou‌,

Thank you for replying.

I solved the issue & I can conclude that any peripherals used in bootloader needs to be reset before jumping so that it attain its initial settings. After resetting USB everything works fine in user application. The below is the one for USB that I used.

LPC_SYSCON->RSTCON[0] = 1<<31;
LPC_SYSCON->RSTCON[0] &= ~(1<<31);

Also it would be preferable to use the same reset code before software reset from user application, otherwise microcontroller will require hard reset.

Regards.

Priyank.

0 Kudos

3,082 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Priyank Bhatt,
I'm glad to hear that your issue has been solved, congratulation.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

3,082 Views
priyankb
Contributor III

Hi jeremyzhou‌,

I understand what you are saying. But my code is going to be large and won't fit in internal flash that is why using external flash.

In bootloader:-

1. changed SP, PC   (values are correct in debug)

2. calling Chip_SetupIrcClocking() for IRC clock.

3. disabling all interrupts & clearing remaining request

4. calling __set_CONTROL(0);       (I don't know if relevant)

This is the user app linker & map file & it looks correct

linker.jpgmapfile.jpg

0 Kudos

3,082 Views
priyankb
Contributor III

Thanks jeremyzhou‌ for your suggestions.

The problem is solved. The reasons being:

1. Usb do not receive exact 64 bytes of packet. They are variable.

2. Writing to flash part needs to be written into Endpoint interrupt handler(as shown below).

ErrorCode_t CDC_bulk_out_handler(USBD_HANDLE_T hUsb, void *data, uint32_t event)
{
    static uint8_t count = 0;
    VCOM_DATA_T *pVcom = (VCOM_DATA_T *) data;

    switch (event) {
    case USB_EVT_OUT:
        pVcom->rx_count = USBD_API->hw->ReadEP(hUsb, USB_CDC_OUT_EP, &val.byte[count]);      //your buffer
        if (pVcom->rx_flags & VCOM_RX_BUF_QUEUED) {
            pVcom->rx_flags &= ~VCOM_RX_BUF_QUEUED;
            if (pVcom->rx_count != 0) {
                pVcom->rx_flags |= VCOM_RX_BUF_FULL;
            }

        }
        else if (pVcom->rx_flags & VCOM_RX_DB_QUEUED) {
            pVcom->rx_flags &= ~VCOM_RX_DB_QUEUED;
            pVcom->rx_flags |= VCOM_RX_DONE;
        }
        //*********************************************************//
        count += pVcom->rx_count;
        if(count%4 == 0)
        {
            WriteFlash(addr, (uint16_t*)val.bit_32, count);
            addr += count;
            count = 0;
        }
        //*********************************************************//
        break;

    case USB_EVT_OUT_NAK:
        /* queue free buffer for RX */
        if ((pVcom->rx_flags & (VCOM_RX_BUF_FULL | VCOM_RX_BUF_QUEUED)) == 0) {
            USBD_API->hw->ReadReqEP(hUsb, USB_CDC_OUT_EP, pVcom->rx_buff, VCOM_RX_BUF_SZ);
            pVcom->rx_flags |= VCOM_RX_BUF_QUEUED;
        }
        break;

    default:
        break;
    }

    return LPC_OK;
}

0 Kudos

3,082 Views
priyankb
Contributor III

Thank you jeremyzhou

I understand what you are saying, but in order to send a big executable file(~1MB) there is no other way. Currently I am trying to move it to external SRAM and then to Flash. But I don't think it is a very efficient way of doing it.

Here is my code,

typedef union Generic_Val {
    uint8_t byte[1024];
    uint32_t bit_32[256];
}Generic_val;

Generic_val Value;

while (1) {
        /* Check if host has connected and opened the VCOM port */
        if ((vcom_connected() != 0) && (prompt == 0)) {
            vcom_write((uint8_t *)"Hello World!!\r\n", 15);
            prompt = 1;
        }
        /* If VCOM port is opened echo whatever we receive back to host. */
        if (prompt) {
            rdCnt = vcom_bread(&Value.byte[j], 1024);
            if (rdCnt) {
                vcom_write(&Value.byte[j], rdCnt);
            }
        }

        j += rdCnt;

        if(j == 1024)
        {
            for(i=0; i<256; i++)
                DEBUGOUT("0x%08xh\r\n", Value.bit_32[i]);

            lpc_norflash_erase_sector(addr);
            /* Wait TSE (~25ms) */
            delayMs(25);

            WriteFlash(addr, (uint16_t*)Value.bit_32, 1024);
//
////            code_present = 1;
//            addr += rdCnt;
        }

0 Kudos