Serasidis / STM32_HID_Bootloader

Driverless USB HID bootloader and flashing tool for STM32F10X devices
424 stars 151 forks source link

Flashing High density device not working properly #32

Open TheKikGen opened 4 years ago

TheKikGen commented 4 years ago

First, thanks for this very small bootloader, and for inspiration around HID ! I have tested the last master branch with a STM32103RC (48K RAM/256K Flash), being a HD device. The bootloader was obviously compiled with the PAGE_SIZE=2048 option. => The last page is not flashed, and so, the firmware is corrupted.

It seems that The ISR handle HIDUSB_HandleData doesn't take care of pending bytes at the last round if bytes > 1024 and below 2048.

static void HIDUSB_HandleData(uint8_t *data)
{
(...)
        case 0x00:

            /* Reset Page Command */
            UploadStarted = true;
            CurrentPage = MIN_PAGE;
            CurrentPageOffset = 0;
        break;

        case 0x01:
=> SOMETHING SHOULD BE DONE HERE TO WRITE PENDING BYTES BETWEEN >1024 AND < 2048....

            /* Reboot MCU Command */
            UploadFinished = true;
        break;

        default:
            break;
        }
    } else if (CurrentPageOffset >= 
(...)

On the other end, using the same buffer for page data and commands is a bit risky.

I have written a version with some optimization , allowing the auto detection of page size (i.e. density) by reading the flash size info from the device. I also use state transitions, rather than booleans to manage the bootloader state. I push here my version of HIDUSB_HandleData

I have also separated page data from USB data until we are sure that it is page data after a full 64 bytes packet received.

static void HIDUSB_HandleData(uint8_t *data)
{
    bool writePage = false;

    memcpy(USB_Buffer + CurrentPacketOffset, data, MAX_PACKET_SIZE);
    CurrentPacketOffset += MAX_PACKET_SIZE;

    if ( CurrentPacketOffset < MAX_BUFFER_SIZE ) return;
    CurrentPacketOffset = 0;
    uint8_t cmd  = HIDUSB_PacketIsCommand();

    if ( cmd == CMD_START ) {
            BootloaderState = BTL_STARTED;
            return;
    }

    if ( cmd == CMD_END ) {
        if (CurrentPageOffset) writePage = true;
        BootloaderState = BTL_END;
    }
    else if (BootloaderState == BTL_STARTED) {
        memcpy(PageData + CurrentPageOffset, USB_Buffer, MAX_BUFFER_SIZE);
        CurrentPageOffset += MAX_BUFFER_SIZE;
        if ( CurrentPageOffset % 1024 == 0) {
                USB_SendData(ENDP1, (uint16_t *) CMD_SIGN, sizeof (CMD_SIGN));
                if (CurrentPageOffset == PageSize ) writePage = true;
        }
    }

    // Write a page to the flash memory
    if ( writePage ) {
            LED1_ON;
            FLASH_WritePage((uint16_t *)(FLASH_BASE_ADDR + CurrentPage * PageSize),
                            (uint16_t *) PageData, CurrentPageOffset / 2);
            CurrentPage++;
            CurrentPageOffset = 0;
            writePage = false;
            LED1_OFF;
    }

}

To save room, and stay below 2K, the USB string descriptors can be commented as they are not really used with generic HID devices.

Hope this helps.

TheKikGen commented 3 years ago

https://github.com/TheKikGen/stm32-tkg-hid-bootloader