;- DeclareModule
DeclareModule DFU
;Define.i
;{ Constants and structures.
Enumeration
#DFU_ChipType_Auto ; Automatic recognition of the microcontroller type.
#DFU_ChipType_FF32 ; FF32 HEX(04d8:f8b9) DEC(1240:63673)
; ATmega
#DFU_ChipType_16U4 ; ATmega16U4
#DFU_ChipType_32U4 ; ATmega32U4
#DFU_ChipType_Max
EndEnumeration
#DFU_ChipType_Unknown = $7F ; Could not determine the type of MC.
Enumeration
#DFU_StartApp_WDT ; Start the program by restarting the MK with the "dog".
#DFU_StartApp_JMP0 ; Start the program by going to the zero address.
EndEnumeration
Enumeration
#DFU_MemType_Flash
#DFU_MemType_EEPROM
EndEnumeration
Enumeration ;- Error codes.
#DFU_Err_OK ; There are no errors.
#DFU_Err_NoInit ; The library is not initialized. You must successfully execute the DFU_Init () function.
#DFU_Err_ChipBad ; Unsupported MK type.
#DFU_Err_Internal ; Внутреняя ошибка программы, например не удалось запросить у системы блок памяти.
#DFU_Err_NotChip ; Не найден МК с заданными PID и VID.
#DFU_Err_OpenDev ; Ошибка установки связи с USB устройством (МК с загрузчиком).
#DFU_Err_ConfigDev; Ошибка конфигурации или интерфейса USB.
#DFU_Err_DevNotRespond ; Загрузчик не ответил на запрос.
#DFU_Err_BadParam ; Некорректный параметр функции.
#DFU_Err_TimeOut ; Выход по таймауту.
#DFU_Err_DownFunct; Ошибка при отправке данных загрузчику.
#DFU_Err_UpFunct ; Ошибка при получении данных от загрузчика.
#DFU_Err_IncorrectFile ; Invalid file.
#DFU_Err_OpenFile ; Could not open file.
#DFU_Err_IncorrectData ; Mismatch data, for example, when checking the recorded firmware in the MK.
#DFU_Err_StatusParam ; Ошибка функции статуса.
#DFU_Err_ProtectMem ; Память защищена.
EndEnumeration
Structure DFU_ChipParam
BootVersion.a ; Версия загрузчика
bootID1.a ; boot ID1 устройства
bootID2.a ; boot ID2 устройства
Manufacturer.a ; Код производителя
Family.a ; Код семейства
ProductName.a ; Имя продукта
Revision.a ; Ревизия продукта
ChipType.b ; Тип микроконтроллера. См. константы DFU_ChipType_xxxx
EndStructure
Structure DFU_CheckInfo ; Информация о верификации памяти.
Address.l ; Адрес первого несовпавшего байта (-1 если все совпали или произошла ошибка).
Res.b ; Результат верификации. Если успешный - больше 0, при несовпадении - 0, при ошибке - меньше 0.
ChipByte.a ; Байт считанный с МК.
BuffByte.a ; Байт находящийся в буфере проверки.
LastErr.l ; Код ошибки.
EndStructure
;}
; It is necessary to call in the beginning of work with the library. Returns not zero if the initialization is successful.
Declare DFU_Init()
; The code of the current error.
Declare.l DFU_GetLastErr()
; Установка связи в МК. См. константы DFU_ChipType_xxxx. Вернет не 0 (DevID) в случае успешного выполнения.
Declare DFU_DevOpen(ChipType.b)
; Разрыв связи с МК. Вернет не 0 в случае успешного выполнения.
Declare DFU_DevClose(*DevID)
; Стирание памяти программ. Вернет отрицательное число в случае ошибки.
Declare DFU_EraseFlash(*DevID)
; Запуск основной программы из загрузчика. См. константы #DFU_StartApp_xxxx.
Declare DFU_StartApp(*DevID, Mode=#DFU_StartApp_WDT)
; Информация о конфигурации и производителе. Вернет не 0 в случае успешного выполнения.
Declare DFU_ChipInfo(*DevID, *Info.DFU_ChipParam)
; Установка адреса CallBack процедуры. Вернет не 0 в случае успешного выполнения.
Declare DFU_SetProgressCB(*DevID, *CB_Proc)
; Прошивка памяти программ микроконтроллера. Вернет не 0 в случае успешного выполнения.
Declare DFU_ProgFlash(*DevID, File.s, *CheckInfo.DFU_CheckInfo=0)
; Прошивка памяти программ микроконтроллера. Вернет не 0 в случае успешного выполнения.
Declare DFU_ProgEEPROM(*DevID, File.s, *CheckInfo.DFU_CheckInfo=0)
; Writes (stitches) to the MK from the buffer * Buff the number of bytes specified in the Size.
; Where to write (Flash or EEPROM depends on the MemType parameter).
; The procedure returns not 0 if successful.
Declare DFU_WriteBuff(*DevID, *Buff, Size, MemType=#DFU_MemType_Flash)
; Reads from the MK to the buffer * Buff the number of bytes specified in the Size.
; Whence it reads (Flash or EEPROM depends on the MemType parameter).
; The procedure returns not 0 if successful.
Declare DFU_ReadBuff(*DevID, *Buff, Size, MemType=#DFU_MemType_Flash)
EndDeclareModule
Module DFU
EnableExplicit
;- Private
;- Constants of DFU.
;{
; DFU commands
#DFU_DETACH = 0
#DFU_DNLOAD = 1
#DFU_UPLOAD = 2
#DFU_GETSTATUS = 3
#DFU_CLRSTATUS = 4
#DFU_GETSTATE = 5
#DFU_ABORT = 6
#USB_CLASS_APP_SPECIFIC = $fe
#DFU_SUBCLASS = $01
#DFU_TIMEOUT = 20000
#DFU_DETACH_TIMEOUT = 1000
; DFU states
#STATE_APP_IDLE = $00
#STATE_APP_DETACH = $01
#STATE_DFU_IDLE = $02
#STATE_DFU_DOWNLOAD_SYNC = $03
#STATE_DFU_DOWNLOAD_BUSY = $04
#STATE_DFU_DOWNLOAD_IDLE = $05
#STATE_DFU_MANIFEST_SYNC = $06
#STATE_DFU_MANIFEST = $07
#STATE_DFU_MANIFEST_WAIT_RESET = $08
#STATE_DFU_UPLOAD_IDLE = $09
#STATE_DFU_ERROR = $0a
;DFU status
#DFU_STATUS_OK = $00
#DFU_STATUS_ERROR_TARGET = $01
#DFU_STATUS_ERROR_FILE = $02
#DFU_STATUS_ERROR_WRITE = $03
#DFU_STATUS_ERROR_ERASE = $04
#DFU_STATUS_ERROR_CHECK_ERASED = $05
#DFU_STATUS_ERROR_PROG = $06
#DFU_STATUS_ERROR_VERIFY = $07
#DFU_STATUS_ERROR_ADDRESS = $08
#DFU_STATUS_ERROR_NOTDONE = $09
#DFU_STATUS_ERROR_FIRMWARE = $0a
#DFU_STATUS_ERROR_VENDOR = $0b
#DFU_STATUS_ERROR_USBR = $0c
#DFU_STATUS_ERROR_POR = $0d
#DFU_STATUS_ERROR_UNKNOWN = $0e
#DFU_STATUS_ERROR_STALLEDPKT = $0f
#ATMEL_USER_PAGE_OFFSET = $80800000
#ATMEL_ERASE_BLOCK_0 = 0
#ATMEL_ERASE_BLOCK_1 = 1
#ATMEL_ERASE_BLOCK_2 = 2
#ATMEL_ERASE_BLOCK_3 = 3
#ATMEL_ERASE_ALL = 4
#ATMEL_SET_CONFIG_BSB = 0
#ATMEL_SET_CONFIG_SBV = 1
#ATMEL_SET_CONFIG_SSB = 2
#ATMEL_SET_CONFIG_EB = 3
#ATMEL_SET_CONFIG_HSB = 4
#ATMEL_SECURE_OFF = 0 ; Security bit is cleared
#ATMEL_SECURE_ON = 1 ; Security bit is set
#ATMEL_SECURE_MAYBE = 2 ; Call To check security bit failed
#ATMEL_64KB_PAGE = $10000
#ATMEL_MAX_TRANSFER_SIZE = $0400
#ATMEL_FOOTER_SIZE = 16
#ATMEL_CONTROL_BLOCK_SIZE = 32
#ATMEL_AVR32_CTRL_BLOCK_SIZE = 64
#ATMEL_MAX_FLASH_BUFFER_SIZE = #ATMEL_MAX_TRANSFER_SIZE +
#ATMEL_AVR32_CTRL_BLOCK_SIZE +
#ATMEL_AVR32_CTRL_BLOCK_SIZE +
#ATMEL_FOOTER_SIZE
#MK_8051 = (1<<0)
#MK_AVR = (1<<1)
#MK_AVR32 = (1<<2)
#MK_XMEGA = (1<<3)
;#DC_STM32 = (1<<4)
#GRP_AVR32 = (#MK_AVR32 | #MK_XMEGA)
#GRP_AVR = (#MK_AVR | #MK_8051)
;#GRP_STM32 = (#DC_STM32)
Enumeration
#mem_flash
#mem_eeprom
#mem_security
#mem_config
#mem_boot
#mem_sig
#mem_user
#mem_ram
#mem_ext0
#mem_ext1
#mem_ext2
#mem_ext3
#mem_ext4
#mem_ext5
#mem_ext6
#mem_ext7
#mem_extdf
EndEnumeration
;Enumeration
#MemType_Flash = #DFU_MemType_Flash
#MemType_EEPROM = #DFU_MemType_EEPROM
;EndEnumeration
;}
;- **** DFU Programmer ****
IncludeFile "libusb.pbi"
Prototype pProgressCB(Percent)
Declare SetProgress(*DevID, Pos, Ends)
Declare GetFlashBlock(*DevID, *Buff, Start, Ends, MemEnd, Type)
;{ Structure
Structure ArrA
a.a[0]
EndStructure
Structure UsbID
PID.u
VID.u
EndStructure
Structure UsbParam Extends UsbID
Array Arr.UsbID(0)
EndStructure
Structure DFU_Status
bStatus.a
bwPollTimeout.l
bState.a
iString.a
EndStructure
Structure DevID_AVR Extends UsbID
ChipType.b ; Type of microcontroller. See the constants DFU_ChipType_xxxx
DevType.a ; Type MK (#ADC_AVR, #ADC_XMEGA, # ADC_AVR32 and so on).
*ProgressCB.pProgressCB
EndStructure
Structure DevID
hDev.i
usbInterface.i
Transaction.i
Avr.DevID_AVR
EndStructure
;}
Global gInitLibState = #False
CompilerIf #PB_Compiler_Thread
Threaded gLastErr.l = 0
CompilerElse
Global gLastErr.l = 0
CompilerEndIf
Procedure SetLastErr(ErrCode.l)
gLastErr = ErrCode
EndProcedure
Procedure TransferIn(*DevID.DevID, Request, Value, *Data, Size)
Protected Res = 0
If *DevID And *DevID\hDev
Res = usb_control_msg(*DevID\hDev, #USB_ENDPOINT_IN | #USB_TYPE_CLASS | #USB_RECIP_INTERFACE,
Request, Value, *DevID\usbInterface, *Data, Size, #DFU_TIMEOUT)
EndIf
ProcedureReturn Res
EndProcedure
Procedure TransferOut(*DevID.DevID, Request, Value, *Data, Size)
Protected Res = 0
If *DevID And *DevID\hDev
Res = usb_control_msg(*DevID\hDev, #USB_ENDPOINT_OUT | #USB_TYPE_CLASS | #USB_RECIP_INTERFACE,
Request, Value, *DevID\usbInterface, *Data, Size, #DFU_TIMEOUT)
EndIf
ProcedureReturn Res
EndProcedure
Procedure Detach(*DevID.DevID, Timeout)
ProcedureReturn TransferOut(*DevID, #DFU_DETACH, Timeout, #Null, 0)
EndProcedure
Procedure Download(*DevID.DevID, *Data, Size)
Protected Res
Res = TransferOut(*DevID, #DFU_DNLOAD, *DevID\Transaction, *Data, Size)
*DevID\Transaction+1
ProcedureReturn Res
EndProcedure
Procedure Upload(*DevID.DevID, *Data, Size)
Protected Res
Res = TransferIn(*DevID, #DFU_UPLOAD, *DevID\Transaction, *Data, Size)
*DevID\Transaction+1
ProcedureReturn Res
EndProcedure
Procedure GetStatus(*DevID.DevID, *Status.DFU_Status)
Protected Res = 0, Buffer.q = 0
If *Status
*Status\bStatus = #DFU_STATUS_ERROR_UNKNOWN
*Status\bwPollTimeout = 0
*Status\bState = #STATE_DFU_ERROR
*Status\iString = 0
Res = TransferIn(*DevID, #DFU_GETSTATUS, 0, @Buffer, 6)
If Res = 6
*Status\bStatus = PeekA(@Buffer)
*Status\bwPollTimeout = PeekL(@Buffer+1) & $00FFFFFF
*Status\bState = PeekA(@Buffer+4)
*Status\iString = PeekA(@Buffer+5)
Else
Res = 0
EndIf
EndIf
ProcedureReturn Res
EndProcedure
Procedure ClearStatus(*DevID.DevID)
ProcedureReturn TransferOut(*DevID, #DFU_CLRSTATUS, 0, #Null, 0)
EndProcedure
Procedure GetState(*DevID.DevID)
Protected Res = 0, Buffer.a = 0
Res = TransferIn(*DevID, #DFU_GETSTATE, 0, @Buffer, SizeOf(Buffer))
If Res > 0
Res = Buffer
EndIf
ProcedureReturn Res
EndProcedure
Procedure Abort(*DevID.DevID)
ProcedureReturn TransferOut(*DevID, #DFU_ABORT, 0, #Null, 0)
EndProcedure
;- **** libusb0 ****
Procedure FindDevide(*ID.UsbParam) ; Search for a USB device with the required PID and VID.
Debug "- FindDevide()"
Protected *usb_busses.usb_bus
Protected *devices.usb_device
Protected *usb_dev=0, i, Count
If *ID
Debug "-- FindDevide().*ID"
Count = ArraySize(*ID\Arr())
usb_find_busses()
usb_find_devices()
*usb_busses = usb_get_busses()
While *usb_busses
*devices = *usb_busses\devices
Debug "-- FindDevide().*ID.*usb_busses: " + *usb_busses\devices
While *devices
Debug "-- FindDevide().*ID.*usb_busses.*devices"
If *ID\PID<>0 Or *ID\VID<>0
Debug "-- FindDevide().*ID.*usb_busses.*devices.IF"
Debug "-- FindDevide().*ID.*usb_busses.*devices.IF: " + *devices\descriptor\idProduct + " ---- " + *ID\PID
Debug "-- FindDevide().*ID.*usb_busses.*devices.IF: " + *devices\descriptor\idVendor + " ---- " + *ID\VID
If *devices\descriptor\idProduct=*ID\PID And
*devices\descriptor\idVendor=*ID\VID
*usb_dev = *devices
Debug "-- FindDevide().*ID.*usb_busses.*devices.IF: " + *devices\descriptor\idProduct + " ---- " + *ID\PID
Debug "-- FindDevide().*ID.*usb_busses.*devices.IF: " + *devices\descriptor\idVendor + " ---- " + *ID\VID
EndIf
Else
Debug "-- FindDevide().*ID.*usb_busses.*devices.ELSE"
For i=0 To Count
;Debug "-- FindDevide().*ID.Count(" + Count + "): " + *devices\descriptor\idProduct + " ---- " + *ID\Arr(i)\PID
;Debug "-- FindDevide().*ID.Count(" + Count + "): " + *devices\descriptor\idVendor + " ---- " + *ID\Arr(i)\VID
If *devices\descriptor\idProduct=*ID\Arr(i)\PID And
*devices\descriptor\idVendor=*ID\Arr(i)\VID
*ID\PID = *devices\descriptor\idProduct
*ID\VID = *devices\descriptor\idVendor
*usb_dev = *devices
Debug "-- FindDevide().*ID.Count.Count: " + *devices\descriptor\idProduct + " ---- " + *ID\Arr(i)\PID
Debug "-- FindDevide().*ID.Count.Count: " + *devices\descriptor\idVendor + " ---- " + *ID\Arr(i)\VID
Break
EndIf
Next
EndIf
*devices = *devices\Next
Wend
*usb_busses = *usb_busses\Next
Wend
EndIf
ProcedureReturn *usb_dev
EndProcedure
Procedure CloseDevice(hDev)
If hDev
usb_close(hDev)
EndIf
EndProcedure
Procedure DevInterface(*Dev.usb_device)
Debug "- DevInterface()"
Protected Res = -1, c, i
Protected *Config.usb_config_descriptor
Protected *Interface.usb_interface_descriptor
Debug "- DevInterface().bNumConfigurations: " + Str(*Dev\descriptor\bNumConfigurations-1)
For c=0 To *Dev\descriptor\bNumConfigurations-1
Debug "- DevInterface().*Dev\config: " + *Dev\config
Debug "- DevInterface().SizeOf.usb_config_descriptor: " + SizeOf(usb_config_descriptor)
*Config = *Dev\config + (SizeOf(usb_config_descriptor) * c)
Debug "- DevInterface().config: " + *Config
For i=0 To *config\Interface\num_altsetting-1
*Interface = *config\Interface\altsetting + (SizeOf(usb_interface_descriptor) * i)
; As though this check should be, but in "iron" bInterfaceClass and bInterfaceSubClass are equal 0!
; If *Interface\bInterfaceClass = #USB_CLASS_APP_SPECIFIC And
; *Interface\bInterfaceSubClass = #DFU_SUBCLASS
Res = *Interface\bInterfaceNumber
Debug "- DevInterface().Res: " + Res
Break 2
; EndIf
Next
Next
ProcedureReturn Res
EndProcedure
Procedure MakeIdle(*DevID.DevID)
Protected Status.DFU_Status
Protected retries = 4, x=400, Res = #False
Abort(*DevID)
While retries > 0
If GetStatus(*DevID, @Status)=0
ClearStatus(*DevID)
x-1
If x<=0
Break
EndIf
Continue
EndIf
Select Status\bState
Case #STATE_DFU_IDLE
If Status\bStatus = #DFU_STATUS_OK
Res = #True
Break
EndIf
ClearStatus(*DevID)
Case #STATE_DFU_DOWNLOAD_SYNC, #STATE_DFU_DOWNLOAD_IDLE, #STATE_DFU_MANIFEST_SYNC,
#STATE_DFU_UPLOAD_IDLE, #STATE_DFU_DOWNLOAD_BUSY, #STATE_DFU_MANIFEST
Abort(*DevID)
Case #STATE_DFU_ERROR
ClearStatus(*DevID)
Case #STATE_APP_IDLE
Detach(*DevID, #DFU_DETACH_TIMEOUT)
Case #STATE_APP_DETACH, #STATE_DFU_MANIFEST_WAIT_RESET
usb_reset(*DevID\hDev)
EndSelect
retries - 1
Wend
ProcedureReturn Res
EndProcedure
Procedure OpenDevice_Connect(*Dev.usb_device, *DevID.DevID)
Debug "- OpenDevice_Connect()"
Protected hDev=0, x=#False
*DevID\usbInterface = DevInterface(*Dev)
If *DevID\usbInterface>=0
;Debug "-- OpenDevice_Connect().*DevID"
Debug "-- OpenDevice_Connect().*DevID("+*dev+")"
hDev = usb_open(*dev)
Debug "-- OpenDevice_Connect().*DevID.hDev(" + hDev + ")"
*DevID\hDev = hDev
If hDev
Debug "--- OpenDevice_Connect().*DevID.hDev"
Debug "-------(((( " + usb_set_configuration(hDev, 1)
If usb_set_configuration(hDev, 1) = 0
Debug "---- OpenDevice_Connect().*DevID.hDev.usb_set_configuration"
If usb_claim_interface(hDev, *DevID\usbInterface) = 0
Debug "---- OpenDevice_Connect().*DevID.hDev.usb_set_configuration.usb_claim_interface"
If MakeIdle(*DevID)
x=#True
Else
usb_release_interface(hDev, *DevID\usbInterface)
SetLastErr(#DFU_Err_DevNotRespond)
EndIf
Else
SetLastErr(#DFU_Err_ConfigDev)
EndIf
Else
SetLastErr(#DFU_Err_ConfigDev)
EndIf
Else
SetLastErr(#DFU_Err_OpenDev)
EndIf
Else
SetLastErr(#DFU_Err_ConfigDev)
EndIf
If hDev And x=#False
CloseDevice(hDev)
hDev = 0
EndIf
ProcedureReturn hDev
EndProcedure
Procedure OpenDevice(PID.u, VID.u, *DevID.DevID)
Debug "- OpenDevice()"
Protected *Dev, hDev
Protected ID.UsbParam
ID\PID = PID
ID\VID = VID
Debug "- OpenDevice() PID: " + PID + " VID: " + VID
*Dev=FindDevide(@ID)
If *Dev ; Device found.
Debug "-- OpenDevice().*Dev - Found"
hDev = OpenDevice_Connect(*Dev, *DevID)
Else
SetLastErr(#DFU_Err_NotChip)
EndIf
ProcedureReturn hDev
EndProcedure
Procedure OpenMultiDevice(Array ID.UsbID(1), ; An array of USB device identifiers.
*DevID.DevID, ; Device identifier (for other functions).
*ID.UsbID=0) ; If any device is found, its identifier will be written down here.
Debug "- OpenMultiDevice()"
Protected *Dev, hDev=0, ID.UsbParam
If *DevID
Debug "-- OpenMultiDevice().*DevID"
ID\PID = 0
ID\VID = 0
CopyArray(ID(), ID\Arr())
*Dev=FindDevide(@ID)
If *Dev ; Device found.
Debug "--- OpenMultiDevice().*DevID.*Dev"
hDev = OpenDevice_Connect(*Dev, *DevID)
If hDev
Debug "---- OpenMultiDevice().*DevID.*Dev.hDev"
If *ID
*ID\PID = ID\PID
*ID\VID = ID\VID
EndIf
EndIf
Else
SetLastErr(#DFU_Err_NotChip)
EndIf
EndIf
ProcedureReturn hDev
EndProcedure
;- **** Programmer ****
Procedure EraseFlash(*DevID.DevID, Mode=#ATMEL_ERASE_ALL) ; Erasing program memory.
Protected Dim Command.a(3)
Protected Status.DFU_Status
Protected Res = -1, Retries = 0
If *DevID
PokeL(@Command(), $00000004)
Select Mode
Case #ATMEL_ERASE_BLOCK_0 : Command(2) = $00
Case #ATMEL_ERASE_BLOCK_1 : Command(2) = $20
Case #ATMEL_ERASE_BLOCK_2 : Command(2) = $40
Case #ATMEL_ERASE_BLOCK_3 : Command(2) = $80
Case #ATMEL_ERASE_ALL : Command(2) = $FF
Default
SetLastErr(#DFU_Err_BadParam)
ProcedureReturn -2
EndSelect
If Download(*DevID, @Command(), 3) = 3
Repeat
If GetStatus(*DevID, @Status)
If Status\bStatus = #DFU_STATUS_ERROR_NOTDONE And
Status\bState = #STATE_DFU_DOWNLOAD_BUSY
Delay(100)
Else
If Status\bStatus = #DFU_STATUS_ERROR_WRITE
SetLastErr(#DFU_Err_ProtectMem)
Else
Res = Status\bStatus
EndIf
Break
EndIf
Else
ClearStatus(*DevID)
EndIf
Retries+1
If Retries > 20
SetLastErr(#DFU_Err_TimeOut)
Break
EndIf
ForEver
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
Procedure StartApp(*DevID.DevID, Mode=#DFU_StartApp_WDT) ; Run the main program from the bootloader.
Protected Dim Command.a(4)
Protected Res = #False, Size=0
If *DevID
If Mode=#DFU_StartApp_WDT
PokeL(@Command(), $00000304)
Size = 3
ElseIf Mode=#DFU_StartApp_JMP0
PokeL(@Command(), $00010304)
Command(4) = 0
Size = 5
EndIf
If Size>0
If Download(*DevID, @Command(), Size) = Size
If Download(*DevID, 0, 0) = 0
Res = #True
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Choice of the memory block MK (only for Xmega and AVR32).
Procedure SelectMemoryUnit(*DevID.DevID, Unit)
Protected Dim Command.a(3)
Protected Status.DFU_Status
Protected Res = #False
If *DevID\Avr\DevType & #GRP_AVR32
If Unit>=0 And Unit <= #mem_extdf
PokeL(@Command(), $00000306)
Command(3) = Unit & 255
If Download(*DevID, @Command(), 4) = 4
If GetStatus(*DevID, @Status)
If Status\bStatus = #DFU_STATUS_OK
Res = #True
Else
If Status\bState = #STATE_DFU_ERROR
ClearStatus(*DevID)
EndIf
EndIf
Else
SetLastErr(#DFU_Err_StatusParam)
EndIf
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
EndIf
Else
Res = #True
EndIf
ProcedureReturn Res
EndProcedure
; Selecting the memory page of the MC. The page size is 64 KB.
Procedure SelectMemoryPage(*DevID.DevID, Page.u)
Protected Dim Command.a(5)
Protected Status.DFU_Status
Protected Res = #False, Size = 0
If *DevID\Avr\DevType & #GRP_AVR32
PokeL(@Command(), $00010306)
Command(3) = (Page>>8) & 255
Command(4) = Page & 255
Size = 5
ElseIf *DevID\Avr\DevType = #MK_AVR
PokeL(@Command(), $00000306)
Command(3) = Page & $FF
Size = 4
EndIf
If Size = 0 Or Download(*DevID, @Command(), Size) = Size
If GetStatus(*DevID, @Status)
If Status\bStatus = #DFU_STATUS_OK
Res = #True
Else
If Status\bState = #STATE_DFU_ERROR
ClearStatus(*DevID)
EndIf
EndIf
EndIf
ElseIf Size > 0
SetLastErr(#DFU_Err_DownFunct)
EndIf
ProcedureReturn Res
EndProcedure
; Reading Configuration Information (Configuration Information)
; or manufacturer information (Manufacturer Information)
Procedure ReadCommand(*DevID.DevID, Data0.a, Data1.a)
Protected Dim Command.a(3)
Protected Status.DFU_Status
Protected Res = -1
If *DevID\Avr\DevType & #GRP_AVR32
If SelectMemoryUnit(*DevID, Data0)
If GetFlashBlock(*DevID.DevID, @Command(), Data1, Data1, -1, #MemType_Flash)
Res = Command(Data1)
EndIf
EndIf
Else
PokeL(@Command(), $00000005)
Command(1) = Data0
Command(2) = Data1
If Download(*DevID, @Command(), 3) = 3
If GetStatus(*DevID, @Status)
If Status\bStatus = #DFU_STATUS_OK
Res = 0
If Upload(*DevID, @Res, 1) <> 1
Res = -2
EndIf
Else
ClearStatus(*DevID)
EndIf
Else
SetLastErr(#DFU_Err_StatusParam)
EndIf
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
EndIf
ProcedureReturn Res
EndProcedure
; Formation of the header for recording data in the MC.
Procedure SetFlashHeader(*Header.ArrA, Start, Size, Type)
Protected Res = #False
If *Header And Start>=0 And Size>0 And (Type=#MemType_Flash Or Type=#MemType_EEPROM)
*Header\a[0] = 1 ; Start programming.
*Header\a[1] = Bool(Type=#MemType_EEPROM) ; Flash или EEPROM.
; Start address.
*Header\a[2] = (Start>>8) & 255
*Header\a[3] = Start & 255
; End address.
*Header\a[4] = (Size>>8) & 255
*Header\a[5] = Size & 255
Res = #True
EndIf
ProcedureReturn Res
EndProcedure
Procedure SetFlashFooter(*Message.ArrA, *Footer.ArrA, PID.u, VID.u)
Protected CRC.l=0, Res = #False
If *Message And *Footer
;PokeL(*Footer, CRC) ; TODO - there must be a CRC calculation.
*Footer\a[0] = (CRC>>24) & 255
*Footer\a[1] = (CRC>>16) & 255
*Footer\a[2] = (CRC>>8) & 255
*Footer\a[3] = CRC & 255
*Footer\a[4] = 16 ; Length of suffix.
*Footer\a[5] = 'D' & 255 ; Signature.
*Footer\a[6] = 'F' & 255
*Footer\a[7] = 'U' & 255
*Footer\a[8] = $01
*Footer\a[9] = $10
*Footer\a[10] = (VID>>8) & 255
*Footer\a[11] = VID & 255
*Footer\a[12] = (PID>>8) & 255
*Footer\a[13] = PID & 255
*Footer\a[14] = $FF
*Footer\a[15] = $FF
; PokeU(@*Footer\a[8], $0100)
; PokeU(@*Footer\a[10], VID)
; PokeU(@*Footer\a[12], PID)
; PokeU(@*Footer\a[14], $FFFF) ; Device release number or FFFFh
Res = #True
EndIf
ProcedureReturn Res
EndProcedure
; Запись блока в флеш.
Procedure SetFlashBlock(*DevID.DevID, *Buff.ArrA, Start, Ends, MemEnd, Type)
Protected Dim Message.a(#ATMEL_MAX_FLASH_BUFFER_SIZE)
Protected *Header.ArrA, *Data.ArrA, *Footer
Protected Status.DFU_Status
Protected Res = #False, i, Length, x
Protected ControlBlockSize, Alignment=0
Length = Ends - Start
If *DevID And *Buff And Start=>0 And Length>0 And Length < #ATMEL_64KB_PAGE And
(Type=#MemType_Flash Or Type=#MemType_EEPROM)
If *DevID\Avr\DevType & #GRP_AVR32
ControlBlockSize = #ATMEL_AVR32_CTRL_BLOCK_SIZE
Alignment = Start % #ATMEL_AVR32_CTRL_BLOCK_SIZE
Else
ControlBlockSize = #ATMEL_CONTROL_BLOCK_SIZE
Alignment = 0
EndIf
*Header = @Message(0)
*Data = @Message(ControlBlockSize + Alignment)
*Footer = *Data + Length
If SetFlashHeader(*Header, Start % #ATMEL_64KB_PAGE,
(Ends-1) % #ATMEL_64KB_PAGE, Type)
If *DevID\Avr\DevType & #MK_XMEGA
*Header\a[1] = 0
EndIf
Length-1
For i=0 To Length
*Data\a[i] = *Buff\a[Start+i]
Next i
If SetFlashFooter(@Message(), *Footer, *DevID\Avr\PID, *DevID\Avr\VID)
Length = *Footer - *Header + #ATMEL_FOOTER_SIZE
If Download(*DevID, @Message(), Length) = Length
If GetStatus(*DevID, @Status)
If Status\bStatus = #DFU_STATUS_OK
Res = #True
Else
If Status\bState = #STATE_DFU_ERROR
ClearStatus(*DevID)
EndIf
SetLastErr(#DFU_Err_StatusParam)
EndIf
Else
SetLastErr(#DFU_Err_StatusParam)
EndIf
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
SetProgress(*DevID, Ends, MemEnd)
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Запись в флеш-память МК.
Procedure SetFlash(*DevID.DevID,
*Buff, ; Адрес буфера с данными.
Size, ; Размер буфера в байтах.
Start, ; Стартовый адрес (начиная с 0) куда записывать данные.
Type) ; Тип памяти. См. константы #MemType_xxxx.
Protected Res = #True
Protected x, i, MemPage
Protected Pos, MemEnd
If *DevID And *Buff And Size>0 And Start>=0 And (Type=#MemType_Flash Or Type=#MemType_EEPROM)
If Type=#MemType_Flash
x=#mem_flash
Else
x=#mem_eeprom
EndIf
If SelectMemoryUnit(*DevID, x)
Pos = Start
MemEnd = Start + Size - 1
MemPage = Start / #ATMEL_64KB_PAGE
If SelectMemoryPage(*DevID, MemPage)
SetProgress(*DevID, 0, 0)
While Pos < MemEnd
If MemPage <> Pos / (#ATMEL_64KB_PAGE-1)
MemPage = Pos / (#ATMEL_64KB_PAGE-1)
If SelectMemoryPage(*DevID, MemPage) = #False ; Ошибка!
Res = #False
SetLastErr(#DFU_Err_DownFunct)
Break
EndIf
EndIf
If MemEnd-Pos > #ATMEL_MAX_TRANSFER_SIZE
x=#ATMEL_MAX_TRANSFER_SIZE
Else
x = MemEnd - Pos + 1
EndIf
If SetFlashBlock(*DevID, *Buff, Pos, x+Pos, MemEnd, Type) = #False
Res = #False
Break
EndIf
Pos + x
Wend
Else
Res = #False
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
Res = #False
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
Res = #False
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Чтение блока
Procedure GetFlashBlock(*DevID.DevID, *Buff.ArrA, Start, Ends, MemEnd, Type)
Protected Dim Command.a(5)
Protected Status.DFU_Status
Protected Res = #False, Length
If Start = Ends
Ends + 1
EndIf
Length = Ends - Start
If *DevID And *Buff And Start>=0 And Length>0 And Length<#ATMEL_64KB_PAGE And
(Type=#MemType_Flash Or Type=#MemType_EEPROM)
Command(0) = $03
If Type=#MemType_EEPROM And *DevID\Avr\DevType & #GRP_AVR
Command(1) = 2
EndIf
Command(2) = (Start>>8) & 255
Command(3) = Start & 255
Command(4) = ((Ends-1)>>8) & 255
Command(5) = (Ends-1) & 255
If Download(*DevID, @Command(), 6) = 6
If Upload(*DevID, *Buff+Start, Length) = Length
If GetStatus(*DevID, @Status)
If Status\bStatus = #DFU_STATUS_OK
Res = #True
Else
If Status\bStatus = #DFU_STATUS_ERROR_FILE
SetLastErr(#DFU_Err_ProtectMem)
Else
SetLastErr(#DFU_Err_StatusParam)
EndIf
ClearStatus(*DevID)
EndIf
Else
SetLastErr(#DFU_Err_StatusParam)
EndIf
Else
SetLastErr(#DFU_Err_UpFunct)
EndIf
Else
SetLastErr(#DFU_Err_DownFunct)
EndIf
SetProgress(*DevID, Ends, MemEnd)
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Reading flash.
Procedure GetFlash(*DevID.DevID,
*Buff, ; The address of the buffer with data.
Size, ; The size of the buffer in bytes.
Start, ; Start address (starting from 0) where to write data.
Type) ; Type of memory. See the constants #MemType_xxxx.
Protected Res = #True
Protected x, i, MemPage
Protected Pos, MemEnd
If *DevID And *Buff And Size>0 And Start>=0 And (Type=#MemType_Flash Or Type=#MemType_EEPROM)
If Type=#MemType_Flash
x=#mem_flash
Else
x=#mem_eeprom
EndIf
If SelectMemoryUnit(*DevID, x)
Pos = Start
MemEnd = Start + Size - 1
MemPage = Start / #ATMEL_64KB_PAGE
If SelectMemoryPage(*DevID, MemPage)
SetProgress(*DevID, 0, 0)
While Pos < MemEnd
If MemPage <> Pos / (#ATMEL_64KB_PAGE-1)
MemPage = Pos / (#ATMEL_64KB_PAGE-1)
If SelectMemoryPage(*DevID, MemPage) = #False ; Error!
Res = #False
SetLastErr(#DFU_Err_DownFunct)
Break
EndIf
EndIf
If MemEnd-Pos > #ATMEL_MAX_TRANSFER_SIZE ;#ATMEL_64KB_PAGE / 2
x=#ATMEL_MAX_TRANSFER_SIZE ;#ATMEL_64KB_PAGE / 2
Else
x = MemEnd - Pos + 1
EndIf
If GetFlashBlock(*DevID, *Buff, Pos, x+Pos, MemEnd, Type) = #False
Res = #False
Break
EndIf
Pos + x
Wend
Else
Res = #False
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
Res = #False
SetLastErr(#DFU_Err_DownFunct)
EndIf
Else
Res = #False
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
Procedure ProgMK(*DevID.DevID, File.s, Type, *CheckInfo.DFU_CheckInfo=0)
Protected Res = #False, FileID, i, LastErr.l
Protected SizeFile.q, *Buff.ArrA=0, *Check.ArrA=0
FileID = ReadFile(#PB_Any, File)
If FileID
SizeFile = Lof(FileID)
If SizeFile>0 And SizeFile<10000000
*Buff = AllocateMemory(SizeFile)
If *Buff
If ReadData(FileID, *Buff, SizeFile) = SizeFile
Res = SetFlash(*DevID, *Buff, SizeFile, 0, Type)
If *CheckInfo ; You need to perform a memory test.
*CheckInfo\Address = -1
*CheckInfo\Res = -1
If Res
*Check = AllocateMemory(SizeFile)
If *Check
LastErr = DFU_GetLastErr()
If GetFlash(*DevID, *Check, SizeFile, 0, Type)
SizeFile-1
*CheckInfo\Res = 1
For i =0 To SizeFile
If *Buff\a[i]<>*Check\a[i]
*CheckInfo\Res = 0
*CheckInfo\Address = i
*CheckInfo\BuffByte = *Buff\a[i]
*CheckInfo\ChipByte = *Check\a[i]
SetLastErr(#DFU_Err_IncorrectData)
Break
EndIf
Next i
EndIf
FreeMemory(*Check)
*CheckInfo\LastErr = DFU_GetLastErr()
SetLastErr(LastErr)
EndIf
EndIf
EndIf
Else
SetLastErr(#DFU_Err_IncorrectFile)
EndIf
FreeMemory(*Buff)
Else
SetLastErr(#DFU_Err_Internal)
EndIf
Else
SetLastErr(#DFU_Err_IncorrectFile)
EndIf
CloseFile(FileID)
Else
SetLastErr(#DFU_Err_OpenFile)
EndIf
ProcedureReturn Res
EndProcedure
;- **** Misc ****
Procedure DevType(ChipType.b)
Debug "- DevType()"
Protected Res = 0
If ChipType>#DFU_ChipType_Auto And ChipType<#DFU_ChipType_Max
Res = #MK_AVR32
EndIf
ProcedureReturn Res
EndProcedure
Procedure.u TypeToPID(ChipType.b)
Debug "- TypeToPID()"
Protected PID.u = 0
Select ChipType
Case #DFU_ChipType_FF32 : PID = $f8b9 ; FF32 HEX(04d8:f8b9) DEC(1240:63673)
Case #DFU_ChipType_16U4 : PID = $2FF3 ; ATmega16U4
Case #DFU_ChipType_32U4 : PID = $2FF4 ; ATmega32U4
EndSelect
Debug "-- TypeToPID("+PID+") FF32 Hex(04d8:f8b9) DEC(1240:63673)"
ProcedureReturn PID
EndProcedure
Procedure.b PidToType(PID.u)
Debug "- PidToType()"
Protected ChipType.b=-1
Select PID
Case $f8b9 : ChipType = #DFU_ChipType_FF32 ; FF32 HEX(04d8:f8b9) DEC(1240:63673)
Case $2FF3 : ChipType = #DFU_ChipType_16U4
Case $2FF4 : ChipType = #DFU_ChipType_32U4
Default : ChipType = #DFU_ChipType_Unknown
EndSelect
ProcedureReturn ChipType
EndProcedure
Procedure SetProgress(*DevID.DevID, Pos, Ends)
Protected x.f
If *DevID And *DevID\Avr\ProgressCB And Ends>=0
If Pos>0
If Pos<Ends
x = 100 / (Ends/Pos)
Else
x = 100
EndIf
Else
x=0
EndIf
*DevID\Avr\ProgressCB(x)
EndIf
EndProcedure
Macro InitTest()
Debug "- InitTest()"
If gInitLibState <> #True
SetLastErr(#DFU_Err_NoInit)
Debug "-- InitTest(Err_NoInit)"
ProcedureReturn 0
Else
SetLastErr(#DFU_Err_OK)
Debug "-- InitTest(Err_OK)"
EndIf
EndMacro
;- **** Public ****
Procedure DFU_Init() ; It is necessary to call in the beginning of work with the library. Returns not zero if the initialization is successful.
Protected Res = #False, x
usb_init()
Res = #True
gInitLibState = #True
ProcedureReturn Res
EndProcedure
; Код текущей ошибки. См константы DFU_Err_xxxx.
Procedure.l DFU_GetLastErr()
ProcedureReturn gLastErr
EndProcedure
Procedure DFU_DevOpen(ChipType.b) ; Installation of the bluetooth in the MK. See the constants DFU_ChipType_xxxx.
Debug "- DFU_DevOpen()"
Protected *Res = 0, *DevID.DevID
Protected PID.u=$f8b9, VID.u=$04d8, i ; FF32 HEX(04d8:f8b9) DEC(1240:63673)
InitTest()
;If ChipType>=#DFU_ChipType_Auto And ChipType<#DFU_ChipType_Max
*DevID = AllocateMemory(SizeOf(DevID))
Debug "-- DFU_DevOpen().DevID.SizeOf: " + SizeOf(DevID)
If *DevID
Debug "-- DFU_DevOpen().DevID: PASS"
InitializeStructure(*DevID, DevID)
; If ChipType=#DFU_ChipType_Auto
; Debug "-- DFU_DevOpen().DevID.ChipType"
;
; Protected Dim ID.UsbID(#DFU_ChipType_Max-#DFU_ChipType_Auto-2)
; Protected Usb.UsbID
;
; For i=#DFU_ChipType_Auto+1 To #DFU_ChipType_Max-1
; ID(i-1)\VID = VID
; ID(i-1)\PID = TypeToPID(i)
; Debug "-- DFU_DevOpen().DevID.ChipType: VID: " + RSet(Hex(VID), 4, "0") + " PID: " + RSet(Hex(TypeToPID(i)), 4, "0")
; Next i
;
; If OpenMultiDevice(ID(), *DevID, @Usb)
; *DevID\Avr\PID = Usb\PID
; *DevID\Avr\VID = Usb\VID
; *DevID\Avr\ChipType = PidToType(*DevID\Avr\PID)
; *DevID\Avr\DevType = DevType(*DevID\Avr\ChipType)
; *Res = *DevID
; EndIf
;
; Else
Debug "-- DFU_DevOpen().DevID.PID"
PID = TypeToPID(#DFU_ChipType_FF32)
Debug "-- DFU_DevOpen().DevID.PID("+PID+")"
If PID<>0
Debug "-- DFU_DevOpen().DevID.PID0.OpenDevice: PID: " + PID + " VID: " + VID + " DevID: " + *DevID
If OpenDevice(PID, VID, *DevID)
Debug "-- DFU_DevOpen().DevID.OpenDevice"
*DevID\Avr\PID = PID
*DevID\Avr\VID = VID
*DevID\Avr\ChipType = ChipType
*DevID\Avr\DevType = DevType(ChipType)
*Res = *DevID
EndIf
Else
SetLastErr(#DFU_Err_ChipBad)
EndIf
; EndIf
Else
SetLastErr(#DFU_Err_Internal)
EndIf
; Else
; SetLastErr(#DFU_Err_ChipBad)
; EndIf
If *DevID And *Res=0
ClearStructure(*DevID, DevID)
FreeMemory(*DevID)
EndIf
ProcedureReturn *Res
EndProcedure
Procedure DFU_DevClose(*DevID.DevID) ; Разрыв связи с МК.
Protected Res = #False
InitTest()
If *DevID And *DevID\hDev
usb_release_interface(*DevID\hDev, *DevID\usbInterface)
CloseDevice(*DevID\hDev)
*DevID\hDev = 0
ClearStructure(*DevID, DevID)
FreeMemory(*DevID)
Res = #True
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
Procedure DFU_EraseFlash(*DevID.DevID) ; Стирание памяти программ.
InitTest()
ProcedureReturn EraseFlash(*DevID)
EndProcedure
Procedure DFU_StartApp(*DevID.DevID, Mode=#DFU_StartApp_WDT) ; Запуск основной программы из загрузчика
InitTest()
ProcedureReturn StartApp(*DevID, Mode)
EndProcedure
Macro GetChipInfo(Info, d1, d2)
x=ReadCommand(*DevID, d1, d2)
If x>=0
Info = x
Else
ProcedureReturn 0
EndIf
EndMacro
Procedure DFU_ChipInfo(*DevID.DevID, *Info.DFU_ChipParam) ; Информаця о конфигурации и производителе.
Protected Res = #False, x
InitTest()
If *DevID And *Info
If *DevID\Avr\DevType & #GRP_AVR32
GetChipInfo(*Info\BootVersion, 4, 0)
GetChipInfo(*Info\bootID1, 4, 1)
GetChipInfo(*Info\bootID2, 4, 2)
GetChipInfo(*Info\Manufacturer, 5, 0)
GetChipInfo(*Info\Family, 5, 1)
GetChipInfo(*Info\ProductName, 5, 2)
GetChipInfo(*Info\Revision, 5, 3)
Else
GetChipInfo(*Info\BootVersion, 0, 0)
GetChipInfo(*Info\bootID1, 0, 1)
GetChipInfo(*Info\bootID2, 0, 2)
GetChipInfo(*Info\Manufacturer, 1, $30)
GetChipInfo(*Info\Family, 1, $31)
GetChipInfo(*Info\ProductName, 1, $60)
GetChipInfo(*Info\Revision, 1, $61)
EndIf
*Info\ChipType = *DevID\Avr\ChipType
Res = #True
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Прошивка памяти программ микроконтроллера.
Procedure DFU_ProgFlash(*DevID.DevID, File.s, *CheckInfo.DFU_CheckInfo=0)
Protected Res = #False
InitTest()
If *DevID
If LCase(GetExtensionPart(File))="bin"
Res = ProgMK(*DevID, File, #MemType_Flash, *CheckInfo)
Else
SetLastErr(#DFU_Err_IncorrectFile)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Прошивка памяти программ микроконтроллера.
Procedure DFU_ProgEEPROM(*DevID.DevID, File.s, *CheckInfo.DFU_CheckInfo=0)
Protected Res = #False
InitTest()
If *DevID
If LCase(GetExtensionPart(File))="eep"
Res = ProgMK(*DevID, File, #MemType_EEPROM, *CheckInfo)
Else
SetLastErr(#DFU_Err_IncorrectFile)
EndIf
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
Procedure DFU_SetProgressCB(*DevID.DevID, *CB_Proc) ; Установка адреса CallBack процедуры.
Protected Res = #False
InitTest()
If *DevID
*DevID\Avr\ProgressCB = *CB_Proc
Res = #True
Else
SetLastErr(#DFU_Err_BadParam)
EndIf
ProcedureReturn Res
EndProcedure
; Записывает (прошивает) в МК из буфера *Buff число байт заданное в Size.
; Куда запишет (Flash или EEPROM зависит от параметра MemType).
; Процедура вернет не 0 в случае успешного выполнения.
Procedure DFU_WriteBuff(*DevID.DevID, *Buff, Size, MemType=#DFU_MemType_Flash)
InitTest()
ProcedureReturn SetFlash(*DevID, *Buff, Size, 0, MemType)
EndProcedure
; Считывает из МК в буфер *Buff число байт заданное в Size.
; Откуда читает (Flash или EEPROM зависит от параметра MemType).
; Процедура вернет не 0 в случае успешного выполнения.
Procedure DFU_ReadBuff(*DevID.DevID, *Buff, Size, MemType=#DFU_MemType_Flash)
InitTest()
ProcedureReturn GetFlash(*DevID, *Buff, Size, 0, MemType)
EndProcedure
EndModule