diff --git a/Examples/MAX78002/QSPI/.vscode/settings.json b/Examples/MAX78002/QSPI/.vscode/settings.json index fa8723b49a..b86fff3f0b 100755 --- a/Examples/MAX78002/QSPI/.vscode/settings.json +++ b/Examples/MAX78002/QSPI/.vscode/settings.json @@ -55,7 +55,8 @@ "${config:MAXIM_PATH}/Libraries/MiscDrivers/PushButton", "${config:MAXIM_PATH}/Libraries/MiscDrivers/Touchscreen", "${config:MAXIM_PATH}/Libraries/MiscDrivers/EEPROM", - "${config:MAXIM_PATH}/Libraries/MiscDrivers/CODEC" + "${config:MAXIM_PATH}/Libraries/MiscDrivers/CODEC", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/SRAM" ], "C_Cpp.default.browse.path": [ "${workspaceFolder}", @@ -72,7 +73,8 @@ "${config:MAXIM_PATH}/Libraries/MiscDrivers", "${config:MAXIM_PATH}/Libraries/MiscDrivers/ADC", "${config:MAXIM_PATH}/Libraries/MiscDrivers/EEPROM", - "${config:MAXIM_PATH}/Libraries/MiscDrivers/CODEC" + "${config:MAXIM_PATH}/Libraries/MiscDrivers/CODEC", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/SRAM" ], "C_Cpp.default.defines": [ diff --git a/Examples/MAX78002/QSPI/aps6404.h b/Examples/MAX78002/QSPI/aps6404.h deleted file mode 100644 index a054d2ad90..0000000000 --- a/Examples/MAX78002/QSPI/aps6404.h +++ /dev/null @@ -1,56 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by - * Analog Devices, Inc.), - * Copyright (C) 2023-2024 Analog Devices, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ -#ifndef EXAMPLES_MAX78002_QSPI_APS6404_H_ -#define EXAMPLES_MAX78002_QSPI_APS6404_H_ - -#include - -#define MFID_EXPECTED 0x0D -#define KGD_EXPECTED 0x5D -#define DENSITY_EXPECTED 0b010 - -typedef struct { - uint8_t MFID; - uint8_t KGD; - uint8_t density; - int EID; -} ram_id_t; - -int ram_init(void); - -int ram_reset(void); - -int ram_enter_quadmode(void); - -int ram_exit_quadmode(void); - -int ram_read_id(ram_id_t *out); - -int ram_read_slow(uint32_t address, uint8_t *out, unsigned int len); - -int ram_read_quad(uint32_t address, uint8_t *out, unsigned int len); - -int ram_write(uint32_t address, uint8_t *data, unsigned int len); - -int ram_write_quad(uint32_t address, uint8_t *data, unsigned int len); - -int benchmark_dma_overhead(unsigned int *out); - -#endif // EXAMPLES_MAX78002_QSPI_APS6404_H_ diff --git a/Examples/MAX78002/QSPI/fastspi.c b/Examples/MAX78002/QSPI/fastspi.c deleted file mode 100644 index 5830034283..0000000000 --- a/Examples/MAX78002/QSPI/fastspi.c +++ /dev/null @@ -1,346 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by - * Analog Devices, Inc.), - * Copyright (C) 2023-2024 Analog Devices, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ -#include -#include -#include -#include "fastspi.h" -#include "gpio.h" -#include "mxc_sys.h" -#include "spi.h" -#include "dma.h" -#include "nvic_table.h" -#include "mxc_delay.h" - -int g_tx_channel; -int g_rx_channel; -int g_fill_dummy_bytes = 0; -int g_dummy_len = 0; -uint8_t g_dummy_byte = 0xFF; -bool g_use_dma = false; - -uint8_t *g_rx_buffer; -uint8_t *g_tx_buffer; -uint32_t g_rx_len; -uint32_t g_tx_len; - -// A macro to convert a DMA channel number to an IRQn number -#define GetIRQnForDMAChannel(x) \ - ((IRQn_Type)(((x) == 0) ? DMA0_IRQn : \ - ((x) == 1) ? DMA1_IRQn : \ - ((x) == 2) ? DMA2_IRQn : \ - DMA3_IRQn)) - -void DMA_TX_IRQHandler(void) -{ - volatile mxc_dma_ch_regs_t *ch = - &MXC_DMA->ch[g_tx_channel]; // Cast the pointer for readability in this ISR - uint32_t status = ch->status; - - if (status & MXC_F_DMA_STATUS_CTZ_IF) { // Count-to-Zero (DMA TX complete) - g_tx_done = 1; - ch->status |= MXC_F_DMA_STATUS_CTZ_IF; - } - - if (status & MXC_F_DMA_STATUS_BUS_ERR) { // Bus Error - ch->status |= MXC_F_DMA_STATUS_BUS_ERR; - } -} - -void DMA_RX_IRQHandler(void) -{ - volatile mxc_dma_ch_regs_t *ch = - &MXC_DMA->ch[g_rx_channel]; // Cast the pointer for readability in this ISR - uint32_t status = ch->status; - - if (status & MXC_F_DMA_STATUS_CTZ_IF) { // Count-to-Zero (DMA RX complete) - g_rx_done = 1; - ch->status |= MXC_F_DMA_STATUS_CTZ_IF; - } - - if (status & MXC_F_DMA_STATUS_BUS_ERR) { // Bus Error - ch->status |= MXC_F_DMA_STATUS_BUS_ERR; - } -} - -void processSPI(void) -{ - // Unload any SPI data that has come in - while (g_rx_buffer && (SPI->dma & MXC_F_SPI_DMA_RX_LVL) && g_rx_len > 0) { - *g_rx_buffer++ = SPI->fifo8[0]; - g_rx_len--; - } - - if (g_rx_len <= 0) { - g_rx_done = 1; - } - - // Write any pending bytes out. - while (g_tx_buffer && - (((SPI->dma & MXC_F_SPI_DMA_TX_LVL) >> MXC_F_SPI_DMA_TX_LVL_POS) < MXC_SPI_FIFO_DEPTH) && - g_tx_len > 0) { - SPI->fifo8[0] = *g_tx_buffer++; - g_tx_len--; - } - - if (g_tx_len <= 0) { - g_tx_done = 1; - } -} - -void SPI_IRQHandler(void) -{ - uint32_t status = SPI->intfl; - - if (status & MXC_F_SPI_INTFL_MST_DONE) { // Master done (TX complete) - g_master_done = 1; - SPI->intfl |= MXC_F_SPI_INTFL_MST_DONE; // Clear flag - } - - if (status & MXC_F_SPI_INTFL_RX_THD) { - SPI->intfl |= MXC_F_SPI_INTFL_RX_THD; - if (!g_use_dma) { - // RX threshold has been crossed, there's data to unload from the FIFO - processSPI(); - } - } - - if (status & MXC_F_SPI_INTFL_TX_THD) { - SPI->intfl |= MXC_F_SPI_INTFL_TX_THD; - if (!g_use_dma) { - // TX threshold has been crossed, we need to refill the FIFO - processSPI(); - } - } -} - -int dma_init(void) -{ - int err = MXC_DMA_Init(); - if (err) - return err; - - g_tx_channel = MXC_DMA_AcquireChannel(); - g_rx_channel = MXC_DMA_AcquireChannel(); - if (g_tx_channel < 0 || g_rx_channel < 0) { - return E_NONE_AVAIL; // Failed to acquire DMA channels - } - - // TX Channel - MXC_DMA->ch[g_tx_channel].ctrl &= ~(MXC_F_DMA_CTRL_EN); - MXC_DMA->ch[g_tx_channel].ctrl = - MXC_F_DMA_CTRL_SRCINC | - (0x2F - << MXC_F_DMA_CTRL_REQUEST_POS); // Enable incrementing the src address pointer, set destination to SPI0 TX FIFO (REQSEL = 0x2F) - MXC_DMA->ch[g_tx_channel].ctrl |= - (MXC_F_DMA_CTRL_CTZ_IE | MXC_F_DMA_CTRL_DIS_IE); // Enable CTZ and DIS interrupts - MXC_DMA->inten |= (1 << g_tx_channel); // Enable DMA interrupts - - // RX Channel - MXC_DMA->ch[g_rx_channel].ctrl &= ~(MXC_F_DMA_CTRL_EN); - MXC_DMA->ch[g_rx_channel].ctrl = - MXC_F_DMA_CTRL_DSTINC | - (0x0F - << MXC_F_DMA_CTRL_REQUEST_POS); // Enable incrementing the dest address pointer, set to source to SPI0 RX FIFO (REQSEL = 0x0F) - MXC_DMA->ch[g_rx_channel].ctrl |= - (MXC_F_DMA_CTRL_CTZ_IE | MXC_F_DMA_CTRL_DIS_IE); // Enable CTZ and DIS interrupts - MXC_DMA->inten |= (1 << g_rx_channel); // Enable DMA interrupts - - MXC_NVIC_SetVector(GetIRQnForDMAChannel(g_tx_channel), DMA_TX_IRQHandler); - NVIC_EnableIRQ(GetIRQnForDMAChannel(g_tx_channel)); - NVIC_SetPriority(GetIRQnForDMAChannel(g_tx_channel), 0); - - MXC_NVIC_SetVector(GetIRQnForDMAChannel(g_rx_channel), DMA_RX_IRQHandler); - NVIC_EnableIRQ(GetIRQnForDMAChannel(g_rx_channel)); - NVIC_SetPriority(GetIRQnForDMAChannel(g_tx_channel), 0); - - return err; -} - -int spi_init(void) -{ - // TODO(Jake): Add software-controlled slave select functionality - MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_SPI0); - MXC_SYS_Reset_Periph(MXC_SYS_RESET1_SPI0); - - int err = MXC_GPIO_Config(&spi_pins); - if (err) - return err; - - err = MXC_GPIO_Config(&spi_ss_pin); - if (err) - return err; - - // Set strongest possible drive strength for SPI pins - spi_pins.port->ds0 |= spi_pins.mask; - spi_pins.port->ds1 |= spi_pins.mask; - - // TODO(Jake): Expose some of the config options below - // TODO(Jake): Move QSPI-SRAM specific options into aps6404.c - - SPI->ctrl0 = (1 << MXC_F_SPI_CTRL0_SS_ACTIVE_POS) | // Set SSEL = SS0 - MXC_F_SPI_CTRL0_MST_MODE | // Select controller mode - MXC_F_SPI_CTRL0_EN; // Enable SPI - - SPI->ctrl2 = (8 << MXC_F_SPI_CTRL2_NUMBITS_POS); // Set 8 bits per character - - SPI->sstime = - (1 << MXC_F_SPI_SSTIME_PRE_POS) | // Remove any delay time between SSEL and SCLK edges - (128 << MXC_F_SPI_SSTIME_POST_POS) | (1 << MXC_F_SPI_SSTIME_INACT_POS); - - SPI->dma = MXC_F_SPI_DMA_TX_FIFO_EN | // Enable TX FIFO - (31 << MXC_F_SPI_DMA_TX_THD_VAL_POS) | // Set TX threshold to 31 - MXC_F_SPI_DMA_DMA_TX_EN; // Enable DMA for the TX FIFO - - SPI->inten |= MXC_F_SPI_INTFL_MST_DONE; // Enable the "Transaction complete" interrupt - - SPI->intfl = SPI->intfl; // Clear any any interrupt flags that may already be set - - err = MXC_SPI_SetFrequency(SPI, SPI_SPEED); - if (err) - return err; - - NVIC_EnableIRQ(MXC_SPI_GET_IRQ(MXC_SPI_GET_IDX(SPI))); - MXC_NVIC_SetVector(MXC_SPI_GET_IRQ(MXC_SPI_GET_IDX(SPI)), SPI_IRQHandler); - NVIC_SetPriority(MXC_SPI_GET_IRQ(MXC_SPI_GET_IDX(SPI)), 1); - - err = dma_init(); - - return err; -} - -int spi_transmit(uint8_t *src, uint32_t txlen, uint8_t *dest, uint32_t rxlen, bool deassert, - bool use_dma, bool block) -{ - g_tx_done = 0; - g_rx_done = 0; - g_master_done = 0; - mxc_spi_width_t width = MXC_SPI_GetWidth(SPI); - - // Set the number of bytes to transmit/receive for the SPI transaction - if (width == SPI_WIDTH_STANDARD) { - if (rxlen > txlen) { - /* - In standard 4-wire mode, the RX_NUM_CHAR field of ctrl1 is ignored. - The number of bytes to transmit AND receive is set by TX_NUM_CHAR, - because the hardware always assume full duplex. Therefore extra - dummy bytes must be transmitted to support half duplex. - */ - g_dummy_len = rxlen - txlen; - SPI->ctrl1 = ((txlen + g_dummy_len) << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS); - } else { - SPI->ctrl1 = txlen << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS; - } - } else { // width != SPI_WIDTH_STANDARD - SPI->ctrl1 = (txlen << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS) | - (rxlen << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS); - } - - SPI->dma &= ~(MXC_F_SPI_DMA_TX_FIFO_EN | MXC_F_SPI_DMA_DMA_TX_EN | MXC_F_SPI_DMA_RX_FIFO_EN | - MXC_F_SPI_DMA_DMA_RX_EN); // Disable FIFOs before clearing as recommended by UG - SPI->dma |= (MXC_F_SPI_DMA_TX_FLUSH | MXC_F_SPI_DMA_RX_FLUSH); // Clear the FIFOs - - if (use_dma) { - g_use_dma = true; - // TX - if (txlen > 1) { - // Configure TX DMA channel to fill the SPI TX FIFO - SPI->dma |= (MXC_F_SPI_DMA_TX_FIFO_EN | MXC_F_SPI_DMA_DMA_TX_EN | - (31 << MXC_F_SPI_DMA_TX_THD_VAL_POS)); - SPI->fifo8[0] = src[0]; - // ^ Hardware requires writing the first byte into the FIFO manually. - MXC_DMA->ch[g_tx_channel].src = (uint32_t)(src + 1); - MXC_DMA->ch[g_tx_channel].cnt = txlen - 1; - MXC_DMA->ch[g_tx_channel].ctrl |= MXC_F_DMA_CTRL_SRCINC; - MXC_DMA->ch[g_tx_channel].ctrl |= MXC_F_DMA_CTRL_EN; // Start the DMA - } else if (txlen == 1) { - // Workaround for single-length transactions not triggering CTZ - SPI->dma |= (MXC_F_SPI_DMA_TX_FIFO_EN | MXC_F_SPI_DMA_DMA_TX_EN); - SPI->fifo8[0] = src[0]; // Write first byte into FIFO - g_tx_done = 1; - } else if (txlen == 0 && width == SPI_WIDTH_STANDARD) { - // Configure TX DMA channel to retransmit a dummy byte - SPI->dma |= (MXC_F_SPI_DMA_TX_FIFO_EN | MXC_F_SPI_DMA_DMA_TX_EN); - MXC_DMA->ch[g_tx_channel].src = (uint32_t)&g_dummy_byte; - MXC_DMA->ch[g_tx_channel].cnt = rxlen; - MXC_DMA->ch[g_tx_channel].ctrl &= ~MXC_F_DMA_CTRL_SRCINC; - MXC_DMA->ch[g_tx_channel].ctrl |= MXC_F_DMA_CTRL_EN; // Start the DMA - } - - // RX - if (rxlen > 0) { - // Configure RX DMA channel to unload the SPI RX FIFO - SPI->dma |= (MXC_F_SPI_DMA_RX_FIFO_EN | MXC_F_SPI_DMA_DMA_RX_EN); - MXC_DMA->ch[g_rx_channel].dst = (uint32_t)dest; - MXC_DMA->ch[g_rx_channel].cnt = rxlen; - MXC_DMA->ch[g_rx_channel].ctrl |= MXC_F_DMA_CTRL_EN; // Start the DMA - } - - } else { // !use_dma - g_use_dma = false; - g_rx_buffer = dest; - g_tx_buffer = src; - g_rx_len = rxlen; - g_tx_len = txlen; - - SPI->inten |= MXC_F_SPI_INTEN_MST_DONE; - - if (txlen > 0) { - // Enable TX FIFO & TX Threshold crossed interrupt - SPI->dma |= (MXC_F_SPI_DMA_TX_FIFO_EN); - SPI->inten |= MXC_F_SPI_INTEN_TX_THD; - } - - if (rxlen > 0) { - // Enable RX FIFO & RX Threshold crossed interrupt - SPI->dma |= (MXC_F_SPI_DMA_RX_FIFO_EN); - SPI->inten |= MXC_F_SPI_INTEN_RX_THD; - } - - /* - This processSPI call fills the TX FIFO as much as possible - before launching the transaction. Subsequent FIFO management will - be handled from the SPI_IRQHandler. - */ - processSPI(); - } - - // Start the SPI transaction - SPI->ctrl0 |= MXC_F_SPI_CTRL0_START; - - /* - Handle slave-select (SS) deassertion. This must be done AFTER launching the transaction - to avoid a glitch on the SS line if: - - The SS line is asserted - - We want to deassert the line as part of this transaction - - As soon as the SPI hardware receives CTRL0->START it seems to reinitialize the SS pin based - on the value of CTRL->SS_CTRL, which causes the glitch. - */ - if (deassert) - SPI->ctrl0 &= ~MXC_F_SPI_CTRL0_SS_CTRL; - else - SPI->ctrl0 |= MXC_F_SPI_CTRL0_SS_CTRL; - - if (block) - while (!((g_tx_done && g_master_done) && (src != NULL && txlen > 0)) && - !(g_rx_done && (dest != NULL && rxlen > 0))) {} - - return E_SUCCESS; -} diff --git a/Examples/MAX78002/QSPI/fastspi.h b/Examples/MAX78002/QSPI/fastspi.h deleted file mode 100644 index 62c029986e..0000000000 --- a/Examples/MAX78002/QSPI/fastspi.h +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by - * Analog Devices, Inc.), - * Copyright (C) 2023-2024 Analog Devices, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ -#ifndef EXAMPLES_MAX78002_QSPI_FASTSPI_H_ -#define EXAMPLES_MAX78002_QSPI_FASTSPI_H_ - -#include "fastspi_config.h" - -static volatile bool g_tx_done = 0; -static volatile bool g_rx_done = 0; -static volatile bool g_master_done = 0; - -static const mxc_gpio_cfg_t spi_ss_pin = { .port = SPI_SS_PORT, - .mask = SPI_SS_PIN, - .func = MXC_GPIO_FUNC_ALT1, - .pad = MXC_GPIO_PAD_WEAK_PULL_UP, - .vssel = MXC_GPIO_VSSEL_VDDIOH }; - -static const mxc_gpio_cfg_t spi_pins = { .port = SPI_PINS_PORT, - .mask = SPI_PINS_MASK, - .func = MXC_GPIO_FUNC_ALT1, - .pad = MXC_GPIO_PAD_NONE, - .vssel = MXC_GPIO_VSSEL_VDDIOH }; - -// TODO(Jake): Generalize to multiple SPI instances -int spi_init(void); -int spi_transmit(uint8_t *src, uint32_t txlen, uint8_t *dest, uint32_t rxlen, bool deassert, - bool use_dma, bool block); - -#endif // EXAMPLES_MAX78002_QSPI_FASTSPI_H_ diff --git a/Examples/MAX78002/QSPI/fastspi_config.h b/Examples/MAX78002/QSPI/fastspi_config.h deleted file mode 100644 index 1b8bf55fd9..0000000000 --- a/Examples/MAX78002/QSPI/fastspi_config.h +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by - * Analog Devices, Inc.), - * Copyright (C) 2023-2024 Analog Devices, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ -#ifndef EXAMPLES_MAX78002_QSPI_FASTSPI_CONFIG_H_ -#define EXAMPLES_MAX78002_QSPI_FASTSPI_CONFIG_H_ - -#include "spi.h" -#include "gpio.h" - -// TODO(Jake): Config struct -#define SPI MXC_SPI0 -#define SPI_SPEED 24000000 -// #define SPI_SPEED 1000000 -#define SPI_PINS_PORT MXC_GPIO0 -#define SPI_PINS_MASK \ - (MXC_GPIO_PIN_5 | MXC_GPIO_PIN_6 | MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8 | MXC_GPIO_PIN_9) -#define SPI_SS_PORT MXC_GPIO0 -#define SPI_SS_PIN MXC_GPIO_PIN_4 - -#endif // EXAMPLES_MAX78002_QSPI_FASTSPI_CONFIG_H_ diff --git a/Examples/MAX78002/QSPI/main.c b/Examples/MAX78002/QSPI/main.c index 8d9ae95ff1..8586140bb8 100644 --- a/Examples/MAX78002/QSPI/main.c +++ b/Examples/MAX78002/QSPI/main.c @@ -50,35 +50,20 @@ /***** Functions *****/ -// ***************************************************************************** -int main(void) +// A more in-depth (but less readable) SRAM test. Validates full functionality +// and demonstrates speed improvements of QSPI over standard SPI. For a simpler +// example, see the main function. +int test(void) { - int err = E_NO_ERROR; - unsigned int elapsed = 0; - int fail_count = 0; - - MXC_Delay(MXC_DELAY_SEC(2)); - - // Set the Internal Primary Oscillator for the fastest system clock speed - MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO); - printf("QSPI SRAM Test:\n"); printf("\tTest Address: 0x%x\n", TEST_ADDR); printf("\tTest size: %i bytes\n", TEST_SIZE); printf("\tTest count: %i rows\n", TEST_COUNT); - printf("\tTest speed: %i Hz\n", SPI_SPEED); - - ram_init(); + printf("\tTest speed: %i Hz\n", FASTSPI_SPEED); - printf("Reading ID...\n"); - ram_id_t id; - err = ram_read_id(&id); - if (err) { - printf("Failed to read expected SRAM ID!\n"); - return err; - } - printf("RAM ID:\n\tMFID: 0x%.2x\n\tKGD: 0x%.2x\n\tDensity: 0x%.2x\n\tEID: 0x%x\n", id.MFID, - id.KGD, id.density, id.EID); + int err = E_NO_ERROR; + unsigned int elapsed = 0; + int fail_count = 0; // Time the measurement overhead of our measurement functions MXC_TMR_SW_Start(MXC_TMR0); @@ -96,15 +81,16 @@ int main(void) // Benchmark standard-width SPI write to external SRAM printf("Test 1: Standard SPI write...\n"); + aps6404_exit_quadmode(); MXC_TMR_SW_Start(MXC_TMR0); - ram_write(TEST_ADDR, tx_buffer, TEST_SIZE); + aps6404_write(TEST_ADDR, tx_buffer, TEST_SIZE); elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tDone (%i bytes in %ius)\n", TEST_SIZE, elapsed); // Read and validate printf("Test 2: Validate w/ standard SPI...\n"); MXC_TMR_SW_Start(MXC_TMR0); - ram_read_slow(TEST_ADDR, rx_buffer, TEST_SIZE); + aps6404_read(TEST_ADDR, rx_buffer, TEST_SIZE); elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tRead finished (%i bytes in %ius)\n", TEST_SIZE, elapsed); printf("\tChecking for mismatches...\n"); @@ -118,8 +104,9 @@ int main(void) printf("\tDone\n"); printf("Test 3: Validate w/ QSPI...\n"); + aps6404_enter_quadmode(); MXC_TMR_SW_Start(MXC_TMR0); - ram_read_quad(TEST_ADDR, rx_buffer, TEST_SIZE); + aps6404_read(TEST_ADDR, rx_buffer, TEST_SIZE); elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tRead finished (%i bytes in %ius)\n", TEST_SIZE, elapsed); printf("\tChecking for mismatches...\n"); @@ -140,14 +127,15 @@ int main(void) // Benchmark QSPI write to external SRAM printf("Test 4: QSPI Write...\n"); MXC_TMR_SW_Start(MXC_TMR0); - err = ram_write_quad(TEST_ADDR, tx_buffer, TEST_SIZE); + err = aps6404_write(TEST_ADDR, tx_buffer, TEST_SIZE); elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tDone (%i bytes in %ius)\n", TEST_SIZE, elapsed); // Read and validate printf("Test 5: Validate w/ standard SPI...\n"); + aps6404_exit_quadmode(); MXC_TMR_SW_Start(MXC_TMR0); - ram_read_slow(TEST_ADDR, rx_buffer, TEST_SIZE); + aps6404_read(TEST_ADDR, rx_buffer, TEST_SIZE); elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tRead finished (%i bytes in %ius)\n", TEST_SIZE, elapsed); printf("\tChecking for mismatches...\n"); @@ -164,8 +152,9 @@ int main(void) // Read and validate printf("Test 6: Validate w/ QSPI...\n"); + aps6404_enter_quadmode(); MXC_TMR_SW_Start(MXC_TMR0); - ram_read_quad(TEST_ADDR, rx_buffer, TEST_SIZE); + aps6404_read(TEST_ADDR, rx_buffer, TEST_SIZE); elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tRead finished (%i bytes in %ius)\n", TEST_SIZE, elapsed); printf("\tChecking for mismatches...\n"); @@ -189,17 +178,18 @@ int main(void) printf("Test 7: QSPI Writing across page boundaries...\n", TEST_SIZE, TEST_COUNT); MXC_TMR_SW_Start(MXC_TMR0); for (int i = 0; i < TEST_COUNT; i++) { - ram_write_quad(address, tx_buffer, TEST_SIZE); + aps6404_write(address, tx_buffer, TEST_SIZE); address += TEST_SIZE; } elapsed = MXC_TMR_SW_Stop(MXC_TMR0) - sw_overhead; printf("\tWrote %i bytes in %ius\n", TEST_SIZE * TEST_COUNT, elapsed); printf("Test 8: Validating with standard SPI...\n"); + aps6404_exit_quadmode(); address = TEST_ADDR; int temp = fail_count; for (int i = 0; i < TEST_COUNT; i++) { - ram_read_slow(address, rx_buffer, TEST_SIZE); + aps6404_read(address, rx_buffer, TEST_SIZE); for (int j = 0; j < TEST_SIZE; j++) { if (rx_buffer[j] != tx_buffer[j]) { fail_count++; @@ -216,10 +206,11 @@ int main(void) // Validate printf("Test 9: Validating with QSPI...\n"); + aps6404_enter_quadmode(); address = TEST_ADDR; temp = fail_count; for (int i = 0; i < TEST_COUNT; i++) { - ram_read_quad(address, rx_buffer, TEST_SIZE); + aps6404_read(address, rx_buffer, TEST_SIZE); for (int j = 0; j < TEST_SIZE; j++) { if (rx_buffer[j] != tx_buffer[j]) { fail_count++; @@ -241,5 +232,55 @@ int main(void) } printf("Success!\n"); + + return err; +} + +// ***************************************************************************** +int main(void) +{ + int err = E_NO_ERROR; + MXC_Delay(MXC_DELAY_SEC(2)); + + // Set the Internal Primary Oscillator for the fastest system clock speed + MXC_SYS_Clock_Select(MXC_SYS_CLOCK_IPO); + + printf("Initializing SRAM...\n"); + err = aps6404_init(); + if (err) { + printf("Initalization failed! (error code %i)\n", err); + return err; + } + + // Reading the ID out is a good first step to validate that hardware + // is connected and working properly. + printf("Reading ID...\n"); + aps6404_id_t id; + err = aps6404_read_id(&id); + if (err) { + printf("Failed to read expected SRAM ID!\n"); + return err; + } else { + printf("RAM ID:\n\tMFID: 0x%.2x\n\tKGD: 0x%.2x\n\tDensity: 0x%.2x\n\tEID: 0x%x\n", id.MFID, + id.KGD, id.density, id.EID); + } + + uint8_t tx_data[4] = { 1, 2, 3, 4 }; + uint8_t rx_buffer[4] = { 0, 0, 0, 0 }; + + aps6404_enter_quadmode(); // Quad mode is faster + aps6404_write(TEST_ADDR, tx_data, 4); + aps6404_read(TEST_ADDR, rx_buffer, 4); + + for (int i = 0; i < 4; i++) { + if (tx_data[i] != rx_buffer[i]) { + printf("Simple R/W test failed at index %i! Expected %i but got %i\n", i, tx_data[i], + rx_buffer[i]); + return E_FAIL; + } + } + + // Run a more advanced test and validation. SRAM is fully functional if this passes. + err = test(); return err; } diff --git a/Libraries/Boards/MAX78000/FTHR_RevA/Include/fastspi_config.h b/Libraries/Boards/MAX78000/FTHR_RevA/Include/fastspi_config.h index 75482d08a1..f00fb774e6 100644 --- a/Libraries/Boards/MAX78000/FTHR_RevA/Include/fastspi_config.h +++ b/Libraries/Boards/MAX78000/FTHR_RevA/Include/fastspi_config.h @@ -36,8 +36,10 @@ #define FASTSPI_VSSEL MXC_GPIO_VSSEL_VDDIOH #define FASTSPI_PINS_MASK \ (MXC_GPIO_PIN_5 | MXC_GPIO_PIN_6 | MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8 | MXC_GPIO_PIN_9) + #define FASTSPI_SS_PORT MXC_GPIO0 #define FASTSPI_SS_PIN MXC_GPIO_PIN_10 // (SS2) +#define FASTSPI_SS_NUM 2 // (*) Required GPIO definitions: static const mxc_gpio_cfg_t fastspi_ss_pin = { .port = FASTSPI_SS_PORT, diff --git a/Libraries/Boards/MAX78002/EvKit_V1/Include/fastspi_config.h b/Libraries/Boards/MAX78002/EvKit_V1/Include/fastspi_config.h new file mode 100644 index 0000000000..e37fdd6652 --- /dev/null +++ b/Libraries/Boards/MAX78002/EvKit_V1/Include/fastspi_config.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright (C) 2023-2024 Analog Devices, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#ifndef LIBRARIES_BOARDS_MAX78002_EVKIT_V1_INCLUDE_FASTSPI_CONFIG_H_ +#define LIBRARIES_BOARDS_MAX78002_EVKIT_V1_INCLUDE_FASTSPI_CONFIG_H_ + +/** + * @file fastspi_config.c + * @brief "fastspi" configuration file for MAX78000FTHR board + */ + +#include "spi.h" +#include "gpio.h" + +// (*) Required definitions: +#define FASTSPI_INSTANCE MXC_SPI0 +#define FASTSPI_SPEED 24000000 + +#define FASTSPI_PINS_PORT MXC_GPIO0 +#define FASTSPI_VSSEL MXC_GPIO_VSSEL_VDDIOH +#define FASTSPI_PINS_MASK \ + (MXC_GPIO_PIN_5 | MXC_GPIO_PIN_6 | MXC_GPIO_PIN_7 | MXC_GPIO_PIN_8 | MXC_GPIO_PIN_9) + +#define FASTSPI_SS_PORT MXC_GPIO0 +#define FASTSPI_SS_PIN MXC_GPIO_PIN_4 +#define FASTSPI_SS_NUM 1 + +// (*) Required GPIO definitions: +static const mxc_gpio_cfg_t fastspi_ss_pin = { .port = FASTSPI_SS_PORT, + .mask = FASTSPI_SS_PIN, + .func = MXC_GPIO_FUNC_ALT1, + .pad = MXC_GPIO_PAD_WEAK_PULL_UP, + .vssel = FASTSPI_VSSEL }; + +static const mxc_gpio_cfg_t fastspi_spi_pins = { .port = FASTSPI_PINS_PORT, + .mask = FASTSPI_PINS_MASK, + .func = MXC_GPIO_FUNC_ALT1, + .pad = MXC_GPIO_PAD_NONE, + .vssel = FASTSPI_VSSEL }; + +#endif // LIBRARIES_BOARDS_MAX78002_EVKIT_V1_INCLUDE_FASTSPI_CONFIG_H_ diff --git a/Libraries/Boards/MAX78002/EvKit_V1/board.mk b/Libraries/Boards/MAX78002/EvKit_V1/board.mk index 2705159a7b..df29146716 100644 --- a/Libraries/Boards/MAX78002/EvKit_V1/board.mk +++ b/Libraries/Boards/MAX78002/EvKit_V1/board.mk @@ -92,6 +92,14 @@ PROJ_CFLAGS+=-DCAMERA_OV7692 endif SRCS += sccb.c +# The MAX78002EVKIT has an on-board external APS6404 SRAM. +# Add drivers for it from MiscDrivers. +ifeq "$(RISCV_CORE)" "" +# RISC-V core does not have access to SPI0. Skip drivers +SRCS += fastspi.c +SRCS += aps6404.c +endif + MISC_DRIVERS_DIR ?= $(MAXIM_PATH)/Libraries/MiscDrivers # Where to find BSP source files @@ -102,6 +110,7 @@ VPATH += $(MISC_DRIVERS_DIR)/Display VPATH += $(MISC_DRIVERS_DIR)/LED VPATH += $(MISC_DRIVERS_DIR)/PushButton VPATH += $(MISC_DRIVERS_DIR)/Touchscreen +VPATH += $(MISC_DRIVERS_DIR)/SRAM # Where to find BSP header files @@ -112,5 +121,6 @@ IPATH += $(MISC_DRIVERS_DIR)/Display IPATH += $(MISC_DRIVERS_DIR)/LED IPATH += $(MISC_DRIVERS_DIR)/PushButton IPATH += $(MISC_DRIVERS_DIR)/Touchscreen +IPATH += $(MISC_DRIVERS_DIR)/SRAM include $(MISC_DRIVERS_DIR)/Display/fonts/fonts.mk diff --git a/Examples/MAX78002/QSPI/aps6404.c b/Libraries/MiscDrivers/SRAM/aps6404.c similarity index 51% rename from Examples/MAX78002/QSPI/aps6404.c rename to Libraries/MiscDrivers/SRAM/aps6404.c index 6d6c827f18..0982785ead 100644 --- a/Examples/MAX78002/QSPI/aps6404.c +++ b/Libraries/MiscDrivers/SRAM/aps6404.c @@ -29,6 +29,16 @@ enum MODE { STANDARD_MODE, QUAD_MODE }; typedef enum MODE MODE_t; MODE_t g_current_mode; +// Utility macro for validating an error code. Assumes an 'err' variable +// of type int exists in the macro's context +#define ERR_CHECK(x) \ + { \ + err = (x); \ + if (err != E_NO_ERROR) { \ + return x; \ + } \ + } + inline void _parse_spi_header(uint8_t cmd, uint32_t address, uint8_t *out) { out[0] = cmd; @@ -46,75 +56,75 @@ int _transmit_spi_header(uint8_t cmd, uint32_t address) _parse_spi_header(cmd, address, header); // Transmit header, but keep Chip Select asserted. - spi_transmit(header, 4, NULL, 0, false, true, true); + spi_transmit(header, 4, NULL, 0, false); return err; } -int ram_init() +int aps6404_init() { int err = E_NO_ERROR; - err = spi_init(); - if (err) - return err; - - err = ram_exit_quadmode(); // Protect against quad-mode lock-up - if (err) - return err; - - err = ram_reset(); + ERR_CHECK(spi_init()); + ERR_CHECK(aps6404_reset()); return err; } -int ram_reset() +int aps6404_reset() { int err = E_NO_ERROR; - uint8_t data[2] = { 0x66, 0x99 }; - spi_transmit(&data[0], 1, NULL, 0, true, true, true); - spi_transmit(&data[1], 1, NULL, 0, true, true, true); + ERR_CHECK(aps6404_exit_quadmode()); // Protect against quad-mode lock-up + + uint8_t data[2] = { 0x66, 0x99 }; + ERR_CHECK(spi_transmit(&data[0], 1, NULL, 0, true)); + ERR_CHECK(spi_transmit(&data[1], 1, NULL, 0, true)); return err; } -int ram_enter_quadmode() +int aps6404_enter_quadmode() { int err = E_NO_ERROR; uint8_t tx_data = 0x35; - MXC_SPI_SetWidth(SPI, SPI_WIDTH_STANDARD); - spi_transmit(&tx_data, 1, NULL, 0, true, true, true); - MXC_SPI_SetWidth(SPI, SPI_WIDTH_QUAD); + ERR_CHECK(MXC_SPI_SetWidth(FASTSPI_INSTANCE, SPI_WIDTH_STANDARD)); + ERR_CHECK(spi_transmit(&tx_data, 1, NULL, 0, true)); + ERR_CHECK(MXC_SPI_SetWidth(FASTSPI_INSTANCE, SPI_WIDTH_QUAD)); g_current_mode = QUAD_MODE; return err; } -int ram_exit_quadmode() +int aps6404_exit_quadmode() { int err = E_NO_ERROR; uint8_t tx_data = 0xF5; - MXC_SPI_SetWidth(SPI, SPI_WIDTH_QUAD); - spi_transmit(&tx_data, 1, NULL, 0, true, true, true); - MXC_SPI_SetWidth(SPI, SPI_WIDTH_STANDARD); + ERR_CHECK(MXC_SPI_SetWidth(FASTSPI_INSTANCE, SPI_WIDTH_QUAD)); + ERR_CHECK(spi_transmit(&tx_data, 1, NULL, 0, true)); + ERR_CHECK(MXC_SPI_SetWidth(FASTSPI_INSTANCE, SPI_WIDTH_STANDARD)); g_current_mode = STANDARD_MODE; return err; } -int ram_read_id(ram_id_t *out) +int aps6404_read_id(aps6404_id_t *out) { int err = E_NO_ERROR; uint8_t tx_data = 0x9F; uint8_t rx_data[12]; + bool back_to_quad_mode = false; - if (g_current_mode != STANDARD_MODE) - ram_exit_quadmode(); + if (g_current_mode != STANDARD_MODE) { + // ID fields seem not to support quad mode. + // If we're currently in quad mode, exit it but re-enable it later + aps6404_exit_quadmode(); + back_to_quad_mode = true; + } - spi_transmit(&tx_data, 1, NULL, 0, false, true, true); - spi_transmit(NULL, 0, rx_data, 12, true, true, true); + ERR_CHECK(spi_transmit(&tx_data, 1, NULL, 0, false)); + ERR_CHECK(spi_transmit(NULL, 0, rx_data, 12, true)); out->MFID = rx_data[3]; out->KGD = rx_data[4]; @@ -128,6 +138,10 @@ int ram_read_id(ram_id_t *out) } out->EID = tmp; + if (back_to_quad_mode) { + aps6404_enter_quadmode(); + } + // Validate against expected values if (out->MFID != MFID_EXPECTED) return E_INVALID; @@ -139,70 +153,34 @@ int ram_read_id(ram_id_t *out) return err; } -int ram_read_slow(uint32_t address, uint8_t *out, unsigned int len) -{ - if (g_current_mode != STANDARD_MODE) - ram_exit_quadmode(); - - int err = E_NO_ERROR; - err = _transmit_spi_header(0x03, address); - if (err) - return err; - - return spi_transmit(NULL, 0, out, len, true, true, true); -} - -int ram_read_quad(uint32_t address, uint8_t *out, unsigned int len) +int aps6404_read(uint32_t address, uint8_t *out, unsigned int len) { - if (g_current_mode != QUAD_MODE) - ram_enter_quadmode(); - int err = E_NO_ERROR; - uint8_t header[7]; - memset(header, 0xFF, 7); - // ^ Sending dummy bytes with value 0x00 seems to break QSPI reads... Sending 0xFF works - _parse_spi_header(0xEB, address, header); - err = spi_transmit(&header[0], 7, NULL, 0, false, true, true); - err = spi_transmit(NULL, 0, out, len, true, true, true); + if (g_current_mode == STANDARD_MODE) { + ERR_CHECK(_transmit_spi_header(0x03, address)); + ERR_CHECK(spi_transmit(NULL, 0, out, len, true)); + } else if (g_current_mode == QUAD_MODE) { + uint8_t header[7]; + memset(header, 0xFF, 7); + // ^ Sending dummy bytes with value 0x00 seems to break QSPI reads... Sending 0xFF works + _parse_spi_header(0xEB, address, header); + ERR_CHECK(spi_transmit(&header[0], 7, NULL, 0, false)); + ERR_CHECK(spi_transmit(NULL, 0, out, len, true)); + } return err; } -int ram_write(uint32_t address, uint8_t *data, unsigned int len) -{ - if (g_current_mode != STANDARD_MODE) - ram_exit_quadmode(); - - int err = E_NO_ERROR; - err = _transmit_spi_header(0x02, address); - if (err) - return err; - - return spi_transmit(data, len, NULL, 0, true, true, true); -} - -int ram_write_quad(uint32_t address, uint8_t *data, unsigned int len) +int aps6404_write(uint32_t address, uint8_t *data, unsigned int len) { - if (g_current_mode != QUAD_MODE) - ram_enter_quadmode(); - int err = E_NO_ERROR; - err = _transmit_spi_header(0x38, address); - if (err) - return err; - - return spi_transmit(data, len, NULL, 0, true, true, true); -} - -int benchmark_dma_overhead(unsigned int *out) -{ - uint8_t buffer[5]; - _parse_spi_header(0x02, 0x0, buffer); - - MXC_TMR_SW_Start(MXC_TMR0); - spi_transmit(buffer, 5, NULL, 0, true, true, false); - unsigned int elapsed = MXC_TMR_SW_Stop(MXC_TMR0); - *out = elapsed; - return E_NO_ERROR; + if (g_current_mode == STANDARD_MODE) { + ERR_CHECK(_transmit_spi_header(0x02, address)); + ERR_CHECK(spi_transmit(data, len, NULL, 0, true)); + } else if (g_current_mode == QUAD_MODE) { + ERR_CHECK(_transmit_spi_header(0x38, address)); + ERR_CHECK(spi_transmit(data, len, NULL, 0, true)); + } + return err; } diff --git a/Libraries/MiscDrivers/SRAM/aps6404.h b/Libraries/MiscDrivers/SRAM/aps6404.h new file mode 100644 index 0000000000..f195693d26 --- /dev/null +++ b/Libraries/MiscDrivers/SRAM/aps6404.h @@ -0,0 +1,181 @@ +/****************************************************************************** + * + * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by + * Analog Devices, Inc.), + * Copyright (C) 2023-2024 Analog Devices, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ +#ifndef LIBRARIES_MISCDRIVERS_SRAM_APS6404_H_ +#define LIBRARIES_MISCDRIVERS_SRAM_APS6404_H_ + +#include +#include + +#define MFID_EXPECTED 0x0D +#define KGD_EXPECTED 0x5D +#define DENSITY_EXPECTED 0b010 + +typedef struct { + uint8_t MFID; + uint8_t KGD; + uint8_t density; + int EID; +} aps6404_id_t; + +// ======================================================================================= + +// SPI TRANSPORT LAYER +// - Must be implemented externally (!) + +/** + * @brief Initializes the SPI (Serial Peripheral Interface) module. + * + * This function initializes the SPI module with default settings. It must be + * called before any SPI transactions are performed. + * + * @return An integer status code. 0 indicates success, while a non-zero value + * indicates an error during initialization. + */ +extern int spi_init(void); + +/** + * @brief Transmits and receives data using the SPI module. + * + * This function performs a full-duplex SPI transaction. It transmits data from + * the source buffer and receives data into the destination buffer. The lengths + * of the transmit and receive buffers are specified by txlen and rxlen + * parameters, respectively. + * + * @param[in] src Pointer to the source buffer containing data to be transmitted. + * @param[in] txlen Length of the data to be transmitted, in bytes. + * @param[out] dest Pointer to the destination buffer to store received data. + * @param[in] rxlen Length of the data to be received, in bytes. + * @param[in] deassert Boolean indicating whether to deassert the CS (Chip Select) line + * after the transaction (true) or keep it asserted (false). + * + * @return An integer status code. 0 indicates success, while a non-zero value + * indicates an error during the SPI transaction. + */ +extern int spi_transmit(uint8_t *src, uint32_t txlen, uint8_t *dest, uint32_t rxlen, bool deassert); + +/** + * @brief Exits the quad mode for SPI (Serial Peripheral Interface) communication. + * + * This function is used to exit the quad mode in SPI, if previously enabled. + * Quad mode typically allows for faster data transfer rates by utilizing + * multiple data lines for both input and output. + * + * @return An integer status code. 0 indicates success, while a non-zero value + * indicates an error during the quad mode exit process. + */ +extern int spi_exit_quadmode(void); + +/** + * @brief Enters the quad mode for SPI (Serial Peripheral Interface) communication. + * + * This function is used to enter the quad mode in SPI, enabling the use of + * multiple data lines for both input and output, which can result in faster + * data transfer rates. + * + * @return An integer status code. 0 indicates success, while a non-zero value + * indicates an error during the quad mode entry process. + */ +extern int spi_enter_quadmode(void); + +// ======================================================================================= + +// DRIVER FUNCTIONS + +/** + * @brief Initialize the APS6404 SRAM. + * + * This function initializes the APS6404 SRAM, setting up necessary configurations + * for proper operation. It should be called before any other driver functions. + * + * @return 0 on success, or an error code on failure. + */ +int aps6404_init(void); + +/** + * @brief Reset the SRAM. + * + * This function issues a software reset sequence to the SRAM. It is called automatically + * as the final step of the initialization sequence. Resetting the SRAM will wipe + * all memory contents. + * + * @return 0 on success, or an error code on failure. + */ +int aps6404_reset(void); + +/** + * @brief Enter Quad Mode. + * + * This function puts the APS6404 into Quad SPI Mode for improved data transfer + * throughput. It will remain in quad mode until + * + * @return 0 on success, or an error code on failure. + */ +int aps6404_enter_quadmode(void); + +/** + * @brief Exit Quad Mode. + * + * This function exits Quad Mode for the APS6404 SRAM, returning to standard SPI operation. + * + * @return 0 on success, or an error code on failure. + */ +int aps6404_exit_quadmode(void); + +/** + * @brief Read the ID fields from the APS6404 + * + * This function reads the manufacturer and other ID fields and validates them against + * expected values from the datasheet. + * + * @param out Pointer to an output struct. ID information will be saved into this struct. + * + * @return 0 on success, or an error code if the ID fields do not match what is expected. + */ +int aps6404_read_id(aps6404_id_t *out); + +/** + * @brief Read data from the APS6404. + * + * Operations are initialized to standard SPI by default. To perform QSPI + * operations call @ref aps6404_enter_quadmode first. + * + * @param address The 24-bit memory address to read from. + * @param out Pointer to the buffer where the read data will be stored. + * @param len Number of bytes to read. + * + * @return 0 on success, or an error code on failure. + */ +int aps6404_read(uint32_t address, uint8_t *out, unsigned int len); + +/** + * @brief Write data to the APS6404. + * + * Operations are initialized to standard SPI by default. To perform QSPI + * operations call @ref aps6404_enter_quadmode first. + * + * @param address The 24-bit memory address to write to. + * @param data Pointer to the buffer containing the data to be written. + * @param len Number of bytes to read. + * + * @return 0 on success, or an error code on failure. + */ +int aps6404_write(uint32_t address, uint8_t *data, unsigned int len); + +#endif // LIBRARIES_MISCDRIVERS_SRAM_APS6404_H_ diff --git a/Libraries/MiscDrivers/SRAM/fastspi.c b/Libraries/MiscDrivers/SRAM/fastspi.c index 01072fe35b..de23ddcd86 100644 --- a/Libraries/MiscDrivers/SRAM/fastspi.c +++ b/Libraries/MiscDrivers/SRAM/fastspi.c @@ -27,24 +27,18 @@ #include "nvic_table.h" #include "mxc_delay.h" -int g_tx_channel; -int g_rx_channel; -int g_fill_dummy_bytes = 0; -int g_dummy_len = 0; -uint8_t g_dummy_byte = 0xFF; +static int g_tx_channel; +static int g_rx_channel; +static int g_dummy_len = 0; +static uint8_t g_dummy_byte = 0xFF; -bool g_dma_initialized = false; - -uint8_t *g_rx_buffer; -uint8_t *g_tx_buffer; -uint32_t g_rx_len; -uint32_t g_tx_len; +static bool g_dma_initialized = false; static volatile bool g_tx_done = 0; static volatile bool g_rx_done = 0; static volatile bool g_master_done = 0; -void DMA_TX_IRQHandler(void) +static void DMA_TX_IRQHandler(void) { volatile mxc_dma_ch_regs_t *ch = &MXC_DMA->ch[g_tx_channel]; // Cast the pointer for readability in this ISR @@ -60,7 +54,7 @@ void DMA_TX_IRQHandler(void) } } -void DMA_RX_IRQHandler(void) +static void DMA_RX_IRQHandler(void) { volatile mxc_dma_ch_regs_t *ch = &MXC_DMA->ch[g_rx_channel]; // Cast the pointer for readability in this ISR @@ -76,32 +70,6 @@ void DMA_RX_IRQHandler(void) } } -void processSPI(void) -{ - // Unload any SPI data that has come in - while (g_rx_buffer && (FASTSPI_INSTANCE->dma & MXC_F_SPI_DMA_RX_LVL) && g_rx_len > 0) { - *g_rx_buffer++ = FASTSPI_INSTANCE->fifo8[0]; - g_rx_len--; - } - - if (g_rx_len <= 0) { - g_rx_done = 1; - } - - // Write any pending bytes out. - while (g_tx_buffer && - (((FASTSPI_INSTANCE->dma & MXC_F_SPI_DMA_TX_LVL) >> MXC_F_SPI_DMA_TX_LVL_POS) < - MXC_SPI_FIFO_DEPTH) && - g_tx_len > 0) { - FASTSPI_INSTANCE->fifo8[0] = *g_tx_buffer++; - g_tx_len--; - } - - if (g_tx_len <= 0) { - g_tx_done = 1; - } -} - void FastSPI_IRQHandler(void) { uint32_t status = FASTSPI_INSTANCE->intfl; @@ -188,11 +156,13 @@ int spi_init(void) fastspi_spi_pins.port->ds0 |= fastspi_spi_pins.mask; fastspi_spi_pins.port->ds1 |= fastspi_spi_pins.mask; - FASTSPI_INSTANCE->ctrl0 = - (0b0100 - << MXC_F_SPI_CTRL0_SS_ACTIVE_POS) | // Set SSEL = SS2 <-- TODO(Jake): Improve this when other drivers are added - MXC_F_SPI_CTRL0_MST_MODE | // Select controller mode - MXC_F_SPI_CTRL0_EN; // Enable SPI + FASTSPI_INSTANCE->ctrl0 = MXC_F_SPI_CTRL0_MST_MODE | // Select controller mode + MXC_F_SPI_CTRL0_EN; // Enable SPI + + // Enable hardware slave select. The instance number should be defined + // in "fastspi_config.h". + MXC_SETFIELD(FASTSPI_INSTANCE->ctrl0, MXC_F_SPI_CTRL0_SS_ACTIVE, + FASTSPI_SS_NUM << MXC_F_SPI_CTRL0_SS_ACTIVE_POS); FASTSPI_INSTANCE->ctrl2 = (8 << MXC_F_SPI_CTRL2_NUMBITS_POS); // Set 8 bits per character diff --git a/Libraries/MiscDrivers/libinfo.json b/Libraries/MiscDrivers/libinfo.json index f94a0b3a89..d1cf771802 100644 --- a/Libraries/MiscDrivers/libinfo.json +++ b/Libraries/MiscDrivers/libinfo.json @@ -10,7 +10,8 @@ "PMIC", "PushButton", "Touchscreen", - "CODEC" + "CODEC", + "SRAM" ], "vpaths":[ "ADC", @@ -23,6 +24,7 @@ "PushButton", "Touchscreen", "CODEC", + "SRAM", "./"], "whitelist":"True", "targets":[