2012-05-23 08:58 AM
Hi,
I am trying to modify the option bytes of my ST so I can disable and enable write protection;however, when I am using DfuSe demo it crashes, I am wondering if anybody else has encountered the same issue, or have a possible solution. #dfuse #dfuse-v3.0.02012-06-25 09:57 AM
2012-06-26 11:08 AM
Hi, I actually managed to program the option bytes successfully, I wouldn't use the filter image function, that was giving me a lot of troubles and to Jonas. Are you programming it in c++ or C#? I made my application in C#.
2012-06-26 04:25 PM
The main application is written in C#, however the DfuSe routines are wrapped into a C++ dll which is imported into the C# application. This method made more sense for my application since my DLL also was handling the HID protocol for application communication. The problem that I am running into is erasing and programming the Option Bytes from the DFU file.
My DfuSe File format is setup as follows: DFU Prefix Section Target Prefix (Internal Flash Image) Image Element (Internal Flash Image) (bAlternateId = 0) Target Prefix (Option Bytes Image) TargetElement(Option Bytes Image) (bAlternateId = 1) DFU Suffix Section The DfuSe file can be loaded into the DfuSe Demo app without any issues. I can program the Internal Flash Image without any issues, but when I select the Option Bytes Image and the Option Bytes target the application returns the following error: Target: 01 Error Code: Unexpected error TransferSize: 2048 DFU State: STATE_DFU_ERROR DFU Status: STATUs_errTARGET Request: Clear Status Request CurrentNBlock 0x0000 CurrentLength: 0x0005 Percent: 99% I also am receiving the similar error in my C++ code during the erase function. My function for the erase is shown below. When I select TargetId = 0 and ImageId = 0 the internal flash is erased and programmed without any issues, but when I select TargetId=1 and ImageId=1 I receive the same error for erasing the Option Bytes. I tried removing the STDFUFILES_FilterImageForOperation function but that did not help. I think that I am missing some critical piece of information that is not described in the API documentation. Has anyone had any luck with programming the option bytes with a Dfue file image? Any help is greatly appreciated z4gunn
/*******************************************************************************
Function Name: DfuErase()
Description: Function to erase the enumerated device
Input: DfuFilename - filename of dfu file to erase
TargetId - device target id
ImageId - file image id
Otuput: None
Return: OperationStatus
*******************************************************************************/
uint8_t DfuErase(CString DfuFilename,
BYTE
TargetId,
BYTE
ImageId)
{
/* intermediate variables */
DfuOperStatusTypeDef Status = OperationFailed;
DWORD
dwRet;
HANDLE
hFile;
BYTE
NbImages;
BOOL
bFound;
PMAPPING pMapping;
DWORD
NbAlternates;
BOOL
UpgradeOptimized = TRUE;
/* open dfu file */
dwRet = STDFUFILES_OpenExistingDFUFile((
LPSTR
)(
LPCSTR
)DfuFilename, &hFile, NULL, NULL, NULL, &NbImages);
/* check for file read error */
if
(dwRet != STDFUFILES_NOERROR)
{
return
FileOpenError;
}
/* make sure that image id is less than number of images */
if
(ImageId >= NbImages)
{
/* close file */
STDFUFILES_CloseDFUFile(hFile);
return
ImageNotFound;
}
/* retrieve suitable image from dfu file */
for
(
int
i = 0; i < NbImages; i++)
{
HANDLE
Image;
BYTE
Alt;
/* read image from file */
dwRet = STDFUFILES_ReadImageFromDFUFile(hFile, i, &Image);
/* check if there was no error*/
if
(dwRet == STDFUFILES_NOERROR)
{
/* get alternate settings for image */
if
(STDFUFILES_GetImageAlternate(Image, &Alt) == STDFUFILES_NOERROR)
{
if
(Alt == ImageId)
{
DfuImage = Image;
bFound = TRUE;
break
;
}
/* clean up */
STDFUFILES_DestroyImage(&Image);
}
}
}
/* close file */
STDFUFILES_CloseDFUFile(hFile);
/* check for invalid image */
if
(DfuImage == NULL)
{
return
ImageNotFound;
}
/* create device mapping */
STDFUPRT_CreateMappingFromDevice((
LPSTR
)(
LPCSTR
)DfuContext.szDevLink, &pMapping, &NbAlternates);
/* filter image from upgrade operation*/
dwRet = STDFUFILES_FilterImageForOperation(DfuImage, pMapping + TargetId, OPERATION_ERASE, UpgradeOptimized);
/* destroy mapping */
STDFUPRT_DestroyMapping(&pMapping);
/* set context struct variables */
DfuContext.Operation = OPERATION_ERASE;
DfuContext.bDontSendFFTransfersForUpgrade = TRUE;
DfuContext.hImage = DfuImage;
/* start upgrade process */
dwRet = STDFUPRT_LaunchOperation(&DfuContext, &DfuOperation);
/* check if upgrade process started without error */
if
(dwRet == STDFUPRT_NOERROR)
{
Status = OperationStarted;
}
return
Status;
}
2012-06-27 09:59 AM
Update:
Since the program Option Bytes via DfuSe file does not seem to work, I tried programming the Option Bytes with STDFU_Dnload() functions. I seem to be having better luck, but I am noticing some strange behavior regarding the device DFU enumeration. My code for programming the option bytes is shown below. The behavior that I am noticing is the the device will detach after the option bytes are downloaded and then the device will re-eumerate as a DFU device shortly after. The status that it returns in this ''limbo'' state is ''STATE_IDLE''. This same behavior can also be observed in the DfuSe demo after pressing the ''Apply'' button in the ''Edit Option Bytes'' dialog. This is not a big concern since the option bytes are actually getting programmed properly, but I would just like to understand the cause of the detach-re-attach behavior. Thanks, z4gunn
/*******************************************************************************
Function Name: DfuWrOptionBytes()
Description: Function to write the user data bytes to the option bytes
Input: RDP - pointer to read data protect
USER - the user flag byte
DATA0 - the user data byte 0
DATA1 - the data user byte 1
WRP0 - the write protect byte 0
WRP1 - the write protect byte 1
WRP2 - the write protect byte 2
WRP3 - the write protect byte 3
Output: None
Return: OperationStatus
*******************************************************************************/
uint8_t DfuWrOptionBytes(
BYTE
RDP,
BYTE
USER,
BYTE
DATA0,
BYTE
DATA1,
BYTE
WRP0,
BYTE
WRP1,
BYTE
WRP2,
BYTE
WRP3)
{
/* intermeidate variables */
BYTE
pBuffer[16];
DFUSTATUS DfuStatus;
DWORD
dwRet;
/* open driver and check for error */
if
(STDFU_Open((
LPSTR
)DfuContext.szDevLink, &DfuHandle) == STDFU_NOERROR)
{
return
OperationFailed;
}
/* select current configuration for option bytes and check for error */
if
(STDFU_SelectCurrentConfiguration(&DfuHandle, 0, 0, 1) != STDFU_NOERROR )
{
/* close driver */
STDFU_Close(&DfuHandle);
return
OperationFailed;
}
/* check status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* wait for idle status */
while
(DfuStatus.bState != STATE_DFU_IDLE)
{
/* clear status */
STDFU_Clrstatus(&DfuHandle);
/* check status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
}
/* set address pointer command in buffer */
pBuffer[0] = 0x21;
pBuffer[1] = 0x00;
pBuffer[2] = 0xF8;
pBuffer[3] = 0xFF;
pBuffer[4] = 0x1F;
/* download address pointer command to device */
STDFU_Dnload(&DfuHandle, pBuffer, 5, 0);
/* check status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* wait for download idle status */
while
(DfuStatus.bState != STATE_DFU_DOWNLOAD_IDLE)
{
/* check status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
}
/* update buffer contents */
pBuffer[0] = RDP;
pBuffer[1] = ~RDP;
pBuffer[2] = USER;
pBuffer[3] = ~USER;
pBuffer[4] = DATA0;
pBuffer[5] = ~DATA0;
pBuffer[6] = DATA1;
pBuffer[7] = ~DATA1;
pBuffer[8] = WRP0;
pBuffer[9] = ~WRP0;
pBuffer[10] = WRP1;
pBuffer[11] = ~WRP1;
pBuffer[12] = WRP2;
pBuffer[13] = ~WRP2;
pBuffer[14] = WRP3;
pBuffer[15] = ~WRP3;
/* download data to device */
dwRet = STDFU_Dnload(&DfuHandle, pBuffer, 16, 2);
/* check status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
/* wait while download is busy */
while
(DfuStatus.bState == STATE_DFU_DOWNLOAD_BUSY)
{
/* check status */
STDFU_Getstatus(&DfuHandle, &DfuStatus);
}
/* close driver */
STDFU_Close(&DfuHandle);
/* check status */
if
(dwRet == STDFU_NOERROR)
{
return
OperationSucceeded;
}
else
{
return
OperationFailed;
}
}
2012-06-28 06:30 AM
Hi,
I am able to program the option byte I did it in C#, but what I did was to save a file with an image of the option byte, and download the image to the option bytes using the LaunchOperation. I am not sure if you can Erase the option bytes, I think you can just rewrite them. With the file I havetargetingthe option bytes I don't have to play with the TarSelec thing that in c# is kind of problematic; however I found a way to target the option byte from creating a mapping from the device. This is how I did it.[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public
struct
MAPPINGSECTOR
{
public
UInt32 dwStartAddress;
public
UInt32 dwAliasedAddress;
public
UInt32 dwSectorIndex;
public
UInt32 dwSectorSize;
public
byte
bSectorType;
public
byte
UseForOperation;
}
[StructLayout(LayoutKind.Explicit, Pack = 1, CharSet = CharSet.Auto)]
public
unsafe
struct
UmMAPPING
{
[FieldOffset(0)]
public
byte
nAlternate;
[FieldOffset(1)]
public
char
Name;
[FieldOffset(261)]
public
UInt32 NbSectors;
[FieldOffset(265)]
public
MAPPINGSECTOR* pSectors;
}
#endregion
#region DLL Imports
[DllImport(
''STDFUPRT.dll''
, EntryPoint =
''STDFUPRT_CreateMappingFromDevice''
, CharSet = CharSet.Auto)]
unsafe
public
static
extern
UInt32 STDFUPRT_CreateMappingArrayFromDevice([MarshalAs(UnmanagedType.LPStr)]
string
DFUNAME,
ref
STDFUPRT.UmMAPPING*[] pumMapping,
ref
UInt32 pNbAlternates);
Again this is in c#. I am not sure how to do it in c++ I see you set TarSelect to 1. Also the Option bytes are not supposed to be programmed entirely. When I perform the download it crashed but the bytes I wanted to reprogram are reprogrammed.
2012-06-28 02:23 PM
Hi Marco,
You are absolutely correct about the ERASE not working on the option bytes, which makes a lot of sense. You are also correct that you have to program all 16 option bytes even if you only want to modify just one byte. I still find that the STM will detach right after the OPERATION_UPGRADE is launched, but most of the time it will automatically re-enumerate in DFU mode after about 5-10 seconds. This causes a little bit of hick-up during the upgrade process, but can be handled in the C# application. In terms of the C# application, it made more sense to wrap all these separate STD*.* dll functions into a single C++ DLL that my C# application calls. The import interface for my DLL is rather simple since most of complexities of handles, contexts, etc are taken care of inside the DLL. This is what my dll imports look like:/* imported dll functions */
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuEnumerate(
byte
DeviceId);
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuErase(
string
FileName,
byte
TargetId,
byte
ImageId);
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuDnload(
string
FileName,
byte
TargetId,
byte
ImageId);
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuUpload(
string
FileName,
byte
TargetId,
byte
ImageId);
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuVerify(
string
FileName,
byte
ImageId);
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuStop();
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuStatus();
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuExit();
[DllImport(
''RFHidCom.dll''
)]
public
static
extern
byte
DfuClose();
As you can see only the high level operations are called from C#, which works pretty good with exception of the Option Bytes update, which I am still working on.
z4gunn
2012-06-29 12:24 AM
I believe the boot loader resets the device after writing to the option bytes. See for instance Section 5.1 of AN3156.
Tormod