Skip to content

Commit 479464f

Browse files
authored
Merge pull request #1162 from bitcraze/krichardsson/fix-gap8-flashing
Fix GAP8 flashing problems
2 parents 961f74b + 3fe8a2d commit 479464f

File tree

5 files changed

+481
-53
lines changed

5 files changed

+481
-53
lines changed

src/deck/drivers/src/aideck.c

+66-52
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "queue.h"
5555
#include "stm32fxxx.h"
5656
#include "system.h"
57+
#include "buf2buf.h"
5758

5859
#include "cpx_internal_router.h"
5960
#include "cpx_external_router.h"
@@ -111,73 +112,86 @@ void cpxBootloaderMessage(const CPXPacket_t * packet) {
111112
xEventGroupSetBits(bootloaderSync, CPX_WAIT_FOR_BOOTLOADER_REPLY);
112113
}
113114

114-
static CPXPacket_t bootPacket;
115+
static CPXPacket_t txPacket;
115116

116117
#define FLASH_BUFFER_SIZE 64
117118
static uint8_t flashBuffer[FLASH_BUFFER_SIZE];
118-
static int flashBufferIndex = 0;
119+
static Buf2bufContext_t gap8BufContext;
119120

120-
static bool gap8DeckFlasherWrite(const uint32_t memAddr, const uint8_t writeLen, const uint8_t *buffer, const DeckMemDef_t* memDef) {
121+
static void sendFlashInit(const uint32_t fwSize) {
122+
GAP8BlCmdPacket_t* gap8BlPacket = (GAP8BlCmdPacket_t*)txPacket.data;
121123

122-
cpxInitRoute(CPX_T_STM32, CPX_T_GAP8, CPX_F_BOOTLOADER, &bootPacket.route);
124+
gap8BlPacket->cmd = GAP8_BL_CMD_START_WRITE;
125+
gap8BlPacket->startAddress = 0x40000;
126+
gap8BlPacket->writeSize = fwSize;
127+
txPacket.dataLength = sizeof(GAP8BlCmdPacket_t);
128+
bool writeOk = cpxSendPacketBlockingTimeout(&txPacket, M2T(GAP8_MAX_MEM_WRITE_TIMEOUT_MS));
129+
ASSERT(writeOk);
130+
}
123131

124-
if (memAddr == 0) {
125-
GAP8BlCmdPacket_t* gap8BlPacket = (GAP8BlCmdPacket_t*)bootPacket.data;
132+
static void sendFlashBuffer(const uint32_t size) {
133+
memcpy(&txPacket.data, flashBuffer, size);
134+
txPacket.dataLength = size;
135+
bool writeOk = cpxSendPacketBlockingTimeout(&txPacket, M2T(GAP8_MAX_MEM_WRITE_TIMEOUT_MS));
136+
ASSERT(writeOk);
137+
}
126138

127-
gap8BlPacket->cmd = GAP8_BL_CMD_START_WRITE;
128-
gap8BlPacket->startAddress = 0x40000;
129-
gap8BlPacket->writeSize = *(memDef->newFwSizeP);
130-
bootPacket.dataLength = sizeof(GAP8BlCmdPacket_t);
131-
bool writeOk = cpxSendPacketBlockingTimeout(&bootPacket, M2T(GAP8_MAX_MEM_WRITE_TIMEOUT_MS));
132-
ASSERT(writeOk);
133-
}
139+
static void sendFlashMd5Request(const uint32_t fwSize) {
140+
GAP8BlCmdPacket_t* gap8BlPacket = (GAP8BlCmdPacket_t*)txPacket.data;
141+
gap8BlPacket->cmd = GAP8_BL_CMD_MD5;
142+
gap8BlPacket->startAddress = 0x40000;
143+
gap8BlPacket->writeSize = fwSize;
144+
txPacket.dataLength = sizeof(GAP8BlCmdPacket_t);
145+
bool writeOk = cpxSendPacketBlockingTimeout(&txPacket, M2T(GAP8_MAX_MEM_WRITE_TIMEOUT_MS));
146+
ASSERT(writeOk);
147+
}
148+
149+
static void waitForCpxResponse() {
150+
EventBits_t bits = xEventGroupWaitBits(bootloaderSync,
151+
CPX_WAIT_FOR_BOOTLOADER_REPLY,
152+
pdTRUE, // Clear bits before returning
153+
pdFALSE, // Wait for any bit
154+
M2T(GAP8_MAX_MEM_VERIFY_TIMEOUT_MS));
155+
bool flashWritten = (bits & CPX_WAIT_FOR_BOOTLOADER_REPLY);
156+
ASSERT(flashWritten);
157+
}
158+
159+
static bool gap8DeckFlasherWrite(const uint32_t memAddr, const uint8_t writeLen, const uint8_t *buffer, const DeckMemDef_t* memDef) {
160+
cpxInitRoute(CPX_T_STM32, CPX_T_GAP8, CPX_F_BOOTLOADER, &txPacket.route);
161+
162+
const uint32_t fwSize = *(memDef->newFwSizeP);
134163

135164
// The GAP8 can only flash data in multiples of 4 bytes,
136165
// buffering will guard against this and also speed things up.
137166
// The full binary that will be flashed is multiple of 4.
138167

139-
uint32_t sizeLeftToBufferFull = sizeof(flashBuffer) - flashBufferIndex;
140-
uint32_t sizeAbleToBuffer = sizeLeftToBufferFull < writeLen ? sizeLeftToBufferFull : writeLen;
141-
uint32_t lastAddressToWrite = memAddr + sizeAbleToBuffer;
142-
143-
memcpy(&flashBuffer[flashBufferIndex], buffer, sizeAbleToBuffer);
144-
flashBufferIndex += sizeAbleToBuffer;
145-
146-
if (flashBufferIndex == sizeof(flashBuffer) || lastAddressToWrite == *(memDef->newFwSizeP)) {
147-
memcpy(&bootPacket.data, flashBuffer, flashBufferIndex);
148-
bootPacket.dataLength = flashBufferIndex;
168+
const bool isFirstBuf = (memAddr == 0);
169+
if (isFirstBuf) {
170+
sendFlashInit(fwSize);
171+
buf2bufInit(&gap8BufContext, flashBuffer, FLASH_BUFFER_SIZE);
172+
}
149173

150-
bool writeOk = cpxSendPacketBlockingTimeout(&bootPacket, M2T(GAP8_MAX_MEM_WRITE_TIMEOUT_MS));
151-
ASSERT(writeOk);
174+
buf2bufAddInBuf(&gap8BufContext, buffer, writeLen);
175+
ASSERT(buf2bufBytesAdded(&gap8BufContext) <= fwSize);
176+
while(buf2bufConsumeInBuf(&gap8BufContext)) {
177+
sendFlashBuffer(FLASH_BUFFER_SIZE);
178+
}
179+
buf2bufReleaseInBuf(&gap8BufContext);
152180

153-
flashBufferIndex = 0;
154-
int sizeLeftToBuffer = writeLen - sizeLeftToBufferFull;
155-
if (sizeLeftToBuffer > 0) {
156-
memcpy(&flashBuffer[flashBufferIndex], &buffer[sizeLeftToBufferFull], sizeLeftToBuffer);
157-
flashBufferIndex += sizeLeftToBuffer;
181+
const bool isLastBuf = (buf2bufBytesConsumed(&gap8BufContext) == fwSize);
182+
if (isLastBuf) {
183+
uint32_t size = buf2bufReleaseOutBuf(&gap8BufContext);
184+
if (size > 0) {
185+
sendFlashBuffer(size);
158186
}
159-
}
187+
ASSERT(buf2bufBytesAdded(&gap8BufContext) == buf2bufBytesConsumed(&gap8BufContext));
160188

161-
if (memAddr + writeLen == *(memDef->newFwSizeP)) {
162189
// Request the MD5 checksum of the flashed data. This is only done
163190
// for synchronizing and making sure everything has been written,
164191
// we do not care about the results.
165-
GAP8BlCmdPacket_t* gap8BlPacket = (GAP8BlCmdPacket_t*)bootPacket.data;
166-
gap8BlPacket->cmd = GAP8_BL_CMD_MD5;
167-
gap8BlPacket->startAddress = 0x40000;
168-
gap8BlPacket->writeSize = *(memDef->newFwSizeP);
169-
bootPacket.dataLength = sizeof(GAP8BlCmdPacket_t);
170-
bool writeOk = cpxSendPacketBlockingTimeout(&bootPacket, M2T(GAP8_MAX_MEM_WRITE_TIMEOUT_MS));
171-
ASSERT(writeOk);
172-
173-
EventBits_t bits = xEventGroupWaitBits(bootloaderSync,
174-
CPX_WAIT_FOR_BOOTLOADER_REPLY,
175-
pdTRUE, // Clear bits before returning
176-
pdFALSE, // Wait for any bit
177-
M2T(GAP8_MAX_MEM_VERIFY_TIMEOUT_MS));
178-
bool flashWritten = (bits & CPX_WAIT_FOR_BOOTLOADER_REPLY);
179-
ASSERT(flashWritten);
180-
}
192+
sendFlashMd5Request(fwSize);
193+
waitForCpxResponse();
194+
}
181195

182196
return true;
183197
}
@@ -186,14 +200,14 @@ static bool gap8DeckFlasherWrite(const uint32_t memAddr, const uint8_t writeLen,
186200
static bool isGap8InBootloaderMode = false;
187201

188202
static void resetGap8ToBootloader() {
189-
cpxInitRoute(CPX_T_STM32, CPX_T_ESP32, CPX_F_SYSTEM, &bootPacket.route);
203+
cpxInitRoute(CPX_T_STM32, CPX_T_ESP32, CPX_F_SYSTEM, &txPacket.route);
190204

191-
ESP32SysPacket_t* esp32SysPacket = (ESP32SysPacket_t*)bootPacket.data;
205+
ESP32SysPacket_t* esp32SysPacket = (ESP32SysPacket_t*)txPacket.data;
192206

193207
esp32SysPacket->cmd = ESP32_SYS_CMD_RESET_GAP8;
194-
bootPacket.dataLength = sizeof(ESP32SysPacket_t);
208+
txPacket.dataLength = sizeof(ESP32SysPacket_t);
195209

196-
cpxSendPacketBlocking(&bootPacket);
210+
cpxSendPacketBlocking(&txPacket);
197211
// This should be handled on RX on CPX instead
198212
vTaskDelay(100);
199213
isGap8InBootloaderMode = true;

src/utils/interface/buf2buf.h

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* ,---------, ____ _ __
3+
* | ,-^-, | / __ )(_) /_______________ _____ ___
4+
* | ( O ) | / __ / / __/ ___/ ___/ __ `/_ / / _ \
5+
* | / ,--´ | / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
6+
* +------` /_____/_/\__/\___/_/ \__,_/ /___/\___/
7+
*
8+
* Crazyflie control firmware
9+
*
10+
* Copyright (C) 2022 Bitcraze AB
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU General Public License as published by
14+
* the Free Software Foundation, in version 3.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU General Public License
22+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
23+
*
24+
*
25+
* buf2buf.h - utility for copying buffers when transferring data from one buffer size to another.
26+
* Incoming buffers have one size while outgoing buffers have a different size.
27+
*/
28+
29+
#include <stdint.h>
30+
#include <stdbool.h>
31+
32+
typedef struct {
33+
const uint8_t* inBuf;
34+
uint32_t inBufIndex;
35+
uint32_t inBufSize;
36+
uint32_t added;
37+
38+
uint8_t* outBuf;
39+
uint32_t outBufIndex;
40+
uint32_t outBufSize;
41+
uint32_t consumed;
42+
} Buf2bufContext_t;
43+
44+
/**
45+
* @brief Initialize a context
46+
*
47+
* This function must be called first to initialize the context.
48+
* A pointer to the out-buffer will be stored in the context and the out-buffer should not be modified until released.
49+
*
50+
* @param context A new context
51+
* @param outBuf Pointer to the out buffer (reused over and over)
52+
* @param outBufSize The size of the out buffer
53+
*/
54+
void buf2bufInit(Buf2bufContext_t* context, uint8_t* outBuf, const uint32_t outBufSize);
55+
56+
/**
57+
* @brief Add a new in-buffer
58+
*
59+
* Call this function when a new in-buffer is available. The pointer to the in-buffer will be stored in the context
60+
* and the in-buffer should not be modified until released by a call to buf2bufReleaseInBuf().
61+
*
62+
* @param context The context
63+
* @param inBuf Pointer to the in-buffer
64+
* @param inBufSize The size of the in-buffer
65+
*/
66+
void buf2bufAddInBuf(Buf2bufContext_t* context, const uint8_t* inBuf, const uint32_t inBufSize);
67+
68+
/**
69+
* @brief Consume data from the in-buffer
70+
*
71+
* Copy data from the in-buffer to the out-buffer, may have to be called multiple times if the out-buffer can not
72+
* hold all the data from the in-buffer. If this function returns true, the out-buffer is full and is ready to be
73+
* emptied by the application code. This function should be called repeatedly until it returns false which indicates
74+
* that the in-buffer is fully consumed.
75+
*
76+
* @param context The context
77+
* @return true The out buffer is full and ready to be used
78+
* @return false The in buffer is fully consumed
79+
*/
80+
bool buf2bufConsumeInBuf(Buf2bufContext_t* context);
81+
82+
/**
83+
* @brief Release the in-buffer
84+
*
85+
* Call when in-buffer has been fully consumed to release the in-buffer.
86+
*
87+
* @param context The context
88+
*/
89+
void buf2bufReleaseInBuf(Buf2bufContext_t* context);
90+
91+
/**
92+
* @brief Release the out-buffer
93+
*
94+
* Will release the out-buffer and return the number of bytes of data that remains to be emptied by the application
95+
* code.
96+
*
97+
* @param context
98+
* @return uint32_t
99+
*/
100+
uint32_t buf2bufReleaseOutBuf(Buf2bufContext_t* context);
101+
102+
/**
103+
* @brief The total number of bytes added by in-buffers
104+
*
105+
* @param context The context
106+
* @return uint32_t The number of bytes
107+
*/
108+
static inline uint32_t buf2bufBytesAdded(const Buf2bufContext_t* context) {
109+
return context->added;
110+
}
111+
112+
/**
113+
* @brief The total number of bytes consumed from in-buffers
114+
*
115+
* @param context The context
116+
* @return uint32_t The number of bytes
117+
*/
118+
static inline uint32_t buf2bufBytesConsumed(const Buf2bufContext_t* context) {
119+
return context->consumed;
120+
}

src/utils/src/Kbuild

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ obj-y += cpuid.o
55
obj-y += crc32.o
66
obj-y += debug.o
77
obj-y += eprintf.o
8-
8+
obj-y += buf2buf.o
99
### Implementations for abort(), malloc() and free(), needed to interact with apps written in C++
1010
obj-y += abort.o
1111
obj-y += malloc.o

0 commit comments

Comments
 (0)