mirror of
https://gitlab.com/hyperglitch/jellyfish.git
synced 2025-12-29 23:36:47 +00:00
175 lines
5.1 KiB
C
175 lines
5.1 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2025 Igor Brkic <igor@hyperglitch.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
#include "jf_qspi.h"
|
|
#include <stdio.h>
|
|
#include "queue.h"
|
|
#include "semphr.h"
|
|
|
|
|
|
QSPI_HandleTypeDef *hqspi_ptr = NULL;
|
|
static jf_qspi_request_t current_request = {0};
|
|
|
|
static uint8_t task_queue_buffer[sizeof(jf_qspi_request_t) * 10];
|
|
static StaticQueue_t task_queue_structure;
|
|
static QueueHandle_t task_queue;
|
|
|
|
static SemaphoreHandle_t qspi_mutex;
|
|
|
|
static osThreadId_t task_handle;
|
|
static const osThreadAttr_t task_attributes = {
|
|
.name = "QSPITask",
|
|
.stack_size = 1024,
|
|
};
|
|
|
|
static uint8_t tmp_buff[2] = {0};
|
|
|
|
|
|
static void process_request(jf_qspi_request_t req) {
|
|
// we need to have some payload for the FPGA to process the request properly
|
|
if (req.size==0 || req.buffer==NULL) {
|
|
req.size = 1;
|
|
req.buffer = tmp_buff;
|
|
}
|
|
current_request = req; // save to global var so callbacks can notify the sender
|
|
|
|
QSPI_CommandTypeDef sCommand;
|
|
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand.Instruction = req.command;
|
|
sCommand.AddressMode = QSPI_ADDRESS_4_LINES;
|
|
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
|
|
sCommand.Address = req.address * 2; // address is aligned
|
|
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
sCommand.DataMode = QSPI_DATA_4_LINES;
|
|
sCommand.NbData = req.size;
|
|
sCommand.DummyCycles = 2;
|
|
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if (HAL_QSPI_Command(hqspi_ptr, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
|
|
// error happened, notify requester
|
|
// FIXME
|
|
return;
|
|
}
|
|
|
|
if (req.command == JF_CMD_ADC_READ) {
|
|
HAL_QSPI_Receive_DMA(hqspi_ptr, req.buffer);
|
|
}
|
|
else {
|
|
HAL_QSPI_Transmit_DMA(hqspi_ptr, req.buffer);
|
|
}
|
|
}
|
|
|
|
static void task_func(void *argument) {
|
|
(void) argument;
|
|
|
|
jf_qspi_request_t req;
|
|
|
|
while (true) {
|
|
// wait for a request
|
|
if (xQueueReceive(task_queue, &req, portMAX_DELAY) == pdTRUE) {
|
|
if (xSemaphoreTake(qspi_mutex, portMAX_DELAY) == pdTRUE) {
|
|
process_request(req);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi) {
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
xSemaphoreGiveFromISR(qspi_mutex, &xHigherPriorityTaskWoken);
|
|
if (current_request.notify_task != NULL) {
|
|
vTaskNotifyGiveFromISR(current_request.notify_task, &xHigherPriorityTaskWoken);
|
|
}
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
}
|
|
|
|
|
|
void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef *hqspi) {
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
xSemaphoreGiveFromISR(qspi_mutex, &xHigherPriorityTaskWoken);
|
|
if (current_request.notify_task!=NULL) {
|
|
vTaskNotifyGiveFromISR(current_request.notify_task, &xHigherPriorityTaskWoken);
|
|
}
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
}
|
|
|
|
|
|
bool jf_qspi_add_to_queue(const jf_qspi_command_t command, const uint32_t address, uint8_t *buffer, const uint16_t size, const bool blocking) {
|
|
jf_qspi_request_t req = {
|
|
.command = command,
|
|
.address = address,
|
|
.buffer = buffer,
|
|
.size = size,
|
|
.notify_task = NULL
|
|
};
|
|
if (blocking) {
|
|
req.notify_task = xTaskGetCurrentTaskHandle();
|
|
}
|
|
const BaseType_t ret = xQueueGenericSend(task_queue, &req, portMAX_DELAY, queueSEND_TO_BACK);
|
|
if (req.notify_task!=NULL) {
|
|
// wait for the request to complete
|
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
}
|
|
return ret==pdPASS;
|
|
}
|
|
|
|
|
|
bool jf_qspi_add_to_queue_from_isr(const jf_qspi_command_t command, const uint32_t address, uint8_t *buffer, const uint16_t size) {
|
|
const jf_qspi_request_t req = {
|
|
.command = command,
|
|
.address = address,
|
|
.buffer = buffer,
|
|
.size = size,
|
|
.notify_task = NULL
|
|
};
|
|
const BaseType_t ret = xQueueGenericSendFromISR(task_queue, &req, pdFALSE, queueSEND_TO_BACK);
|
|
return ret==pdPASS;
|
|
}
|
|
|
|
|
|
bool jf_qspi_direct_call(const jf_qspi_command_t command, const uint32_t address, uint8_t *buffer, const uint16_t size) {
|
|
const jf_qspi_request_t req = {
|
|
.command = command,
|
|
.address = address,
|
|
.buffer = buffer,
|
|
.size = size,
|
|
.notify_task = NULL
|
|
};
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
if (xSemaphoreTakeFromISR(qspi_mutex, &xHigherPriorityTaskWoken) == pdTRUE) {
|
|
process_request(req);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void jf_qspi_init(QSPI_HandleTypeDef *hqspi) {
|
|
hqspi_ptr = hqspi;
|
|
qspi_mutex = xSemaphoreCreateBinary();
|
|
if (qspi_mutex != NULL) {
|
|
xSemaphoreGive(qspi_mutex);
|
|
}
|
|
else {
|
|
printf("failed to create qspi mutex\r\n");
|
|
}
|
|
|
|
task_queue = xQueueCreateStatic(
|
|
10,
|
|
sizeof(jf_qspi_request_t),
|
|
task_queue_buffer,
|
|
&task_queue_structure
|
|
);
|
|
if(task_queue == NULL) {
|
|
printf("failed to create qspi queue\r\n");
|
|
Error_Handler();
|
|
}
|
|
|
|
task_handle = osThreadNew(task_func, NULL, &task_attributes);
|
|
printf("\r\nQSPI task created\r\n");
|
|
}
|