0
mirror of https://gitlab.com/hyperglitch/jellyfish.git synced 2025-12-29 23:36:47 +00:00
2025-06-12 10:31:43 +02:00

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");
}