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:
parent
83a98f743c
commit
432b80167f
12 changed files with 341 additions and 265 deletions
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue