1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-26 01:35:41 +03:00

Added non-blocking SPI DMA support for access to FLASH for BB

This commit is contained in:
Steve Evans 2021-04-20 19:45:56 +01:00
parent 83a98f743c
commit 432b80167f
12 changed files with 341 additions and 265 deletions

View file

@ -155,7 +155,7 @@ static void w25n01g_performOneByteCommand(flashDeviceIO_t *io, uint8_t command)
};
// Ensure any prior DMA has completed before continuing
spiWait(dev);
spiWaitClaim(dev);
spiSequence(dev, &segments[0]);
@ -183,7 +183,7 @@ static void w25n01g_performCommandWithPageAddress(flashDeviceIO_t *io, uint8_t c
};
// Ensure any prior DMA has completed before continuing
spiWait(dev);
spiWaitClaim(dev);
spiSequence(dev, &segments[0]);
@ -420,7 +420,7 @@ static void w25n01g_programDataLoad(flashDevice_t *fdevice, uint16_t columnAddre
};
// Ensure any prior DMA has completed before continuing
spiWait(dev);
spiWaitClaim(dev);
spiSequence(dev, &segments[0]);
@ -454,7 +454,7 @@ static void w25n01g_randomProgramDataLoad(flashDevice_t *fdevice, uint16_t colum
};
// Ensure any prior DMA has completed before continuing
spiWait(dev);
spiWaitClaim(dev);
spiSequence(dev, &segments[0]);
@ -521,8 +521,10 @@ static uint32_t programLoadAddress;
bool bufferDirty = false;
bool isProgramming = false;
void w25n01g_pageProgramBegin(flashDevice_t *fdevice, uint32_t address)
void w25n01g_pageProgramBegin(flashDevice_t *fdevice, uint32_t address, void (*callback)(uint32_t length))
{
fdevice->callback = callback;
if (bufferDirty) {
if (address != programLoadAddress) {
w25n01g_waitForReady(fdevice);
@ -541,8 +543,13 @@ void w25n01g_pageProgramBegin(flashDevice_t *fdevice, uint32_t address)
}
}
void w25n01g_pageProgramContinue(flashDevice_t *fdevice, const uint8_t *data, int length)
uint32_t w25n01g_pageProgramContinue(flashDevice_t *fdevice, uint8_t const **buffers, uint32_t *bufferSizes, uint32_t bufferCount)
{
if (bufferCount < 1) {
fdevice->callback(0);
return 0;
}
w25n01g_waitForReady(fdevice);
w25n01g_writeEnable(fdevice);
@ -550,15 +557,21 @@ void w25n01g_pageProgramContinue(flashDevice_t *fdevice, const uint8_t *data, in
isProgramming = false;
if (!bufferDirty) {
w25n01g_programDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), data, length);
w25n01g_programDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), buffers[0], bufferSizes[0]);
} else {
w25n01g_randomProgramDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), data, length);
w25n01g_randomProgramDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), buffers[0], bufferSizes[0]);
}
// XXX Test if write enable is reset after each data loading.
bufferDirty = true;
programLoadAddress += length;
programLoadAddress += bufferSizes[0];
if (fdevice->callback) {
fdevice->callback(bufferSizes[0]);
}
return bufferSizes[0];
}
static uint32_t currentPage = UINT32_MAX;
@ -594,10 +607,10 @@ void w25n01g_pageProgramFinish(flashDevice_t *fdevice)
* break this operation up into one beginProgram call, one or more continueProgram calls, and one finishProgram call.
*/
void w25n01g_pageProgram(flashDevice_t *fdevice, uint32_t address, const uint8_t *data, int length)
void w25n01g_pageProgram(flashDevice_t *fdevice, uint32_t address, const uint8_t *data, uint32_t length, void (*callback)(uint32_t length))
{
w25n01g_pageProgramBegin(fdevice, address);
w25n01g_pageProgramContinue(fdevice, data, length);
w25n01g_pageProgramBegin(fdevice, address, callback);
w25n01g_pageProgramContinue(fdevice, &data, &length, 1);
w25n01g_pageProgramFinish(fdevice);
}
@ -641,7 +654,7 @@ void w25n01g_addError(uint32_t address, uint8_t code)
// (3) Issue READ_DATA on column address.
// (4) Return transferLength.
int w25n01g_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, int length)
int w25n01g_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, uint32_t length)
{
uint32_t targetPage = W25N01G_LINEAR_TO_PAGE(address);
@ -662,7 +675,7 @@ int w25n01g_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer,
currentPage = targetPage;
}
int column = W25N01G_LINEAR_TO_COLUMN(address);
uint32_t column = W25N01G_LINEAR_TO_COLUMN(address);
uint16_t transferLength;
if (length > W25N01G_PAGE_SIZE - column) {
@ -687,7 +700,7 @@ int w25n01g_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer,
};
// Ensure any prior DMA has completed before continuing
spiWait(dev);
spiWaitClaim(dev);
spiSequence(dev, &segments[0]);
@ -800,10 +813,42 @@ const flashVTable_t w25n01g_vTable = {
.getGeometry = w25n01g_getGeometry,
};
typedef volatile struct cb_context_s {
flashDevice_t *fdevice;
bblut_t *bblut;
int lutsize;
int lutindex;
} cb_context_t;
// Called in ISR context
// Read of BBLUT entry has just completed
busStatus_e w25n01g_readBBLUTCallback(uint32_t arg)
{
cb_context_t *cb_context = (cb_context_t *)arg;
flashDevice_t *fdevice = cb_context->fdevice;
uint8_t *rxData = fdevice->io.handle.dev->bus->curSegment->rxData;
cb_context->bblut->pba = (rxData[0] << 16)|rxData[1];
cb_context->bblut->lba = (rxData[2] << 16)|rxData[3];
if (++cb_context->lutindex < cb_context->lutsize) {
cb_context->bblut++;
return BUS_BUSY; // Repeat the operation
}
return BUS_READY; // All done
}
void w25n01g_readBBLUT(flashDevice_t *fdevice, bblut_t *bblut, int lutsize)
{
cb_context_t cb_context;
uint8_t in[4];
cb_context.fdevice = fdevice;
fdevice->callbackArg = (uint32_t)&cb_context;
if (fdevice->io.mode == FLASHIO_SPI) {
extDevice_t *dev = fdevice->io.handle.dev;
@ -812,25 +857,23 @@ void w25n01g_readBBLUT(flashDevice_t *fdevice, bblut_t *bblut, int lutsize)
cmd[0] = W25N01G_INSTRUCTION_READ_BBM_LUT;
cmd[1] = 0;
cb_context.bblut = &bblut[0];
cb_context.lutsize = lutsize;
cb_context.lutindex = 0;
busSegment_t segments[] = {
{cmd, NULL, sizeof (cmd), false, NULL},
{NULL, in, sizeof (in), true, NULL},
{NULL, in, sizeof (in), true, w25n01g_readBBLUTCallback},
{NULL, NULL, 0, true, NULL},
};
// Ensure any prior DMA has completed before continuing
spiWait(dev);
spiWaitClaim(dev);
spiSequence(dev, &segments[0]);
// Block pending completion of SPI access
spiWait(dev);
for (int i = 0 ; i < lutsize ; i++) {
spiReadWriteBuf(dev, NULL, in, 4);
bblut[i].pba = (in[0] << 16)|in[1];
bblut[i].lba = (in[2] << 16)|in[3];
}
}
#ifdef USE_QUADSPI
else if (fdevice->io.mode == FLASHIO_QUADSPI) {