diff --git a/Examples/MAX78002/SPI/README.md b/Examples/MAX78002/SPI/README.md index 7f6f63d8670..e652b0dd18e 100644 --- a/Examples/MAX78002/SPI/README.md +++ b/Examples/MAX78002/SPI/README.md @@ -1,91 +1,16 @@ ## Description -This example configures the SPI to send data between the MISO (P0.22) and -MOSI (P0.21) pins. Connect these two pins together. +This example configures the SPI to send data between the MISO (P0.22) and MOSI (P0.21) pins. Connect these two pins together. Multiple word sizes (2 through 16 bits) are demonstrated. -By default, the example performs blocking SPI transactions. To switch to non-blocking (asynchronous) transactions, reset the BLOCKING macro to 0 and set the NON_BLOCKING macro to 1. To use DMA transactions, set the DMA macro to 1 instead. +By default, the example performs blocking SPI transactions. To switch to non-blocking (asynchronous) transactions, reset the `CONTROLLER_SYNC` macro to 0 and set the `CONTROLLER_ASYNC` macro to 1. To use DMA transactions, set the `CONTROLLER_DMA` macro to 1 instead. -This example also demonstrates the feature to use custom Target Selects that the SPI v2 Driver will automatically assert/deassert during transactions. Set the CUSTOM_TARGET macro to 1 to use the custom target. To use the default TS pins, set the CUSTOM_TARGET macro to 0 instead. +This example uses the Hardware Target Select control scheme (application does not assert the TS pins). ## Software -This example uses the SPI v2 Library. To use the previous SPI library, set `MXC_SPI_BUILD_LEGACY=1` in the Project's project.mk file. - -### Porting Guide - -The SPI v2 Library is backwards compatible with the previous SPI API - meaning the previously existing function prototypes have not changed. There are functional differences with SPI DMA interrupt handling that must be updated when porting a project from using the previous SPI API to SPI v2. - -#### SPI v2 API Differences - -##### SPI Init Function - -The `MXC_SPI_Init(...)` function is still supported with SPI v2, but there is some added overhead due to the limited settings that this function can set. - -Use the `MXC_SPI_Init_v2(...)` function for 1) to decrease overhead and 2) to give the caller more control in the SPI setup. - -**`mxc_spi_init_t init` Fields** -- `mxc_spi_regs_t *spi` //<== SPI Instance -- `mxc_gpio_cfg_t *spi_pins` //<== (Optional) Caller supplied SPI pins. -- `mxc_spi_type_t type` //<== Controller (L. Master) or Target (L. Slave) Modes -- `uint32_t freq` //<== SPI Frequency -- `mxc_spi_clkmode_t clk_mode` //<== Clock Mode (CPOL:CPHA) -- `mxc_spi_interface_t mode` //<== Select Interface (Standard 4-wire, 3-wire, dual, quad) -- `mxc_spi_tscontrol_t ts_control` //<== HW Auto, SW Driver, or SW Application Target Control -- `mxc_spi_target_t target` //<== Target settings (custom TS pins, init mask, active polarity) -- `mxc_gpio_vssel_t vssel` //<== Select Pin Voltage Level (VDDIO/VDDIOH) -- `bool use_dma` //<== TRUE/FALSE DMA setting -- `mxc_dma_regs_t *dma` //<== DMA Instance -- `mxc_spi_callback_t callback` //<== Set Callback function for end of transaction -- `void* callback_data` //<== Data to pass through callback function - -##### SPI DMA Interrupt Handling - -```c -void DMA_TX_IRQHandler(void) -{ - MXC_SPI_DMA_TX_Handler(SPI); -} - -void DMA_RX_IRQHandler(void) -{ - MXC_SPI_DMA_RX_Handler(SPI); -} - -``` -The previous SPI API uses the MXC_DMA_Handler, but SPI v2 supplies its own Handler processing functions to call for TX and RX DMA. - -##### SPI DMA Setup -```c - ... - TX_DMA_CH = MXC_SPI_DMA_GetTXChannel(SPI); - RX_DMA_CH = MXC_SPI_DMA_GetRXChannel(SPI); - - NVIC_EnableIRQ(MXC_DMA_CH_GET_IRQ(TX_DMA_CH)); - NVIC_EnableIRQ(MXC_DMA_CH_GET_IRQ(RX_DMA_CH)); - - MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(TX_DMA_CH), DMA_TX_IRQHandler); - MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(RX_DMA_CH), DMA_RX_IRQHandler); - - MXC_SPI_MasterTransactionDMA(&req); - ... -``` -Following the DMA channel interrupt changes from the previous section, it is recommended to set up a generic name DMA TX/RX vector because the the TX and RX DMA channels won't always acquire DMA_CH0 and DMA_CH1, respectively. - -##### Blocking SPI Transaction (MXC_SPI_MasterTransaction(...)) -```c -void SPI_IRQHandler(void) -{ - MXC_SPI_Handler(SPI); // Or MXC_SPI_AsyncHandler(SPI); Same function, different names. -} - - ... - NVIC_EnableIRQ(SPI); - MXC_SPI_MasterTransaction(&req); - ... -``` -The blocking SPI transaction function is now interrupt driven for SPI v2 - meaning the SPI instances' IRQ must be enabled and the MXC_SPI_Handler(...) or MXC_SPI_AsyncHandler(...) function must be called in the interrupt routine. +This project uses the SPI v2 library. More information on the SPI v2 library can be found in the **[MSDK User Guide Developer Notes](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#spi-v2-library)**. ### Project Usage @@ -93,7 +18,7 @@ Universal instructions on building, flashing, and debugging this project can be ### Project-Specific Build Notes -(None - this project builds as a standard example) +Set `MXC_SPI_VERSION=v2` to build the SPI v2 libraries. ## Required Connections @@ -101,6 +26,7 @@ Universal instructions on building, flashing, and debugging this project can be - Connect the 5V power cable at (5V IN). - Close jumper (RX - P0.0) and (TX - P0.1) at Headers JP23 (UART 0 EN). - Open an terminal application on the PC and connect to the EV kit's console UART at 115200, 8-N-1. +- Connect P0.21 (MOSI) to P0.22 (MISO). ## Expected Output diff --git a/Examples/MAX78002/SPI/main.c b/Examples/MAX78002/SPI/main.c index d54d1d3851f..c41f06a7b51 100644 --- a/Examples/MAX78002/SPI/main.c +++ b/Examples/MAX78002/SPI/main.c @@ -1,10 +1,3 @@ -/** - * @file main.c - * @brief SPI Controller Demo - * @details Shows Controller loopback demo for QSPI0 - * Read the printf() for instructions - */ - /****************************************************************************** * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. * @@ -38,6 +31,12 @@ * ******************************************************************************/ +/** + * @file main.c + * @brief SPI Controller Demo + * @details This example demonstrates the SPI controller loopback transactions. + */ + /***** Includes *****/ #include #include @@ -50,24 +49,25 @@ #include "uart.h" #include "spi.h" #include "dma.h" +#include "led.h" /***** Preprocessors *****/ -#define BLOCKING 1 -#define NON_BLOCKING 0 -#define DMA 0 +#define CONTROLLER_SYNC 0 +#define CONTROLLER_ASYNC 0 +#define CONTROLLER_DMA 1 -#define CUSTOM_TARGET 0 - -#if (!(BLOCKING || NON_BLOCKING || DMA)) -#error "You must set either BLOCKING or NON_BLOCKING or DMA to 1." +// Preprocessor Error Checking +#if (!(CONTROLLER_SYNC || CONTROLLER_ASYNC || CONTROLLER_DMA)) +#error "You must set either CONTROLLER_SYNC or CONTROLLER_ASYNC or CONTROLLER_DMA to 1." #endif -#if ((BLOCKING && NON_BLOCKING) || (NON_BLOCKING && DMA) || (DMA && BLOCKING)) -#error "You must select either BLOCKING or NON_BLOCKING or DMA, not all 3." +#if ((CONTROLLER_SYNC && CONTROLLER_ASYNC) || (CONTROLLER_ASYNC && CONTROLLER_DMA) || \ + (CONTROLLER_DMA && CONTROLLER_SYNC)) +#error "You must select either CONTROLLER_SYNC or CONTROLLER_ASYNC or CONTROLLER_DMA, not all 3." #endif /***** Definitions *****/ #define DATA_LEN 100 // Words -#define DATA_VALUE 0xA5B7 // This is for master mode only... +#define DATA_VALUE 0xA5B7 // This is for Controller mode only... #define VALUE 0xFFFF #define SPI_SPEED 100000 // Bit Rate @@ -115,21 +115,20 @@ int main(void) { int i, j, retVal; uint16_t temp; - mxc_spi_init_t init; - mxc_spi_target_t target; + mxc_spi_cfg_t cfg; printf("\n**************************** SPI CONTROLLER TEST *************************\n"); printf("This example configures the SPI to send data between the MISO (P0.22) and\n"); printf("MOSI (P0.21) pins. Connect these two pins together.\n\n"); printf("Multiple word sizes (2 through 16 bits) are demonstrated.\n\n"); -#if BLOCKING +#if CONTROLLER_SYNC printf("Performing blocking (synchronous) transactions...\n"); #endif -#if NON_BLOCKING +#if CONTROLLER_ASYNC printf("Performing non-blocking (asynchronous) transactions...\n"); #endif -#if DMA +#if CONTROLLER_DMA printf("Performing transactions with DMA...\n"); #endif @@ -139,79 +138,68 @@ int main(void) tx_data[j] = DATA_VALUE; } - // Initialization Settings. - init.spi = SPI; - init.freq = SPI_SPEED; - init.spi_pins = NULL; // Use default, predefined pins - init.mode = MXC_SPI_INTERFACE_STANDARD; // 4-wire - init.type = MXC_SPI_TYPE_CONTROLLER; - init.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 - init.frame_size = i; - init.callback = SPI_Callback; - - // Target Select Settings -#if CUSTOM_TARGET - // Example to select a custom target. - mxc_gpio_cfg_t target_pins; - target_pins.port = MXC_GPIO0; - target_pins.mask = MXC_GPIO_PIN_9; - target_pins.func = MXC_GPIO_FUNC_OUT; - target_pins.pad = MXC_GPIO_PAD_PULL_UP; - target_pins.vssel = MXC_GPIO_VSSEL_VDDIOH; // Set custom target pin to VDDIOH (3.3V). - - init.ts_control = - MXC_SPI_TSCONTROL_SW_DRV; // SPI Driver will handle deassertion for TS pins. - init.target.pins = target_pins; - init.target.active_polarity = 0; - init.vssel = MXC_GPIO_VSSEL_VDDIOH; // Set SPI pins to VDDIOH (3.3V). - - // Select target for transaction. - target.pins = target_pins; // Custom pins -#else - init.ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // HW will deassert/assert TS pins. - init.target.active_polarity = 0; - init.target.init_mask = 0x01; // Initialize Target Select 0 pin. - init.vssel = MXC_GPIO_VSSEL_VDDIO; + mxc_spi_pins_t spi_pins; + // This example enables the TS0 HW pin. + spi_pins.ss0 = true; // TS0 + spi_pins.ss1 = false; // TS1 + spi_pins.ss2 = false; // TS2 + spi_pins.vddioh = true; + spi_pins.drvstr = MXC_GPIO_DRVSTR_0; - // Select target for transaction. - target.index = 0; // TS0 -#endif + retVal = MXC_SPI_Init(SPI, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, 0, 0b000, + SPI_SPEED, spi_pins); + if (retVal != E_NO_ERROR) { + printf("\nSPI INITIALIZATION ERROR\n"); + return retVal; + } + + // SPI Settings. + cfg.spi = SPI; + cfg.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 + cfg.frame_size = i; // DMA Settings. -#if DMA - init.use_dma = true; - init.dma = MXC_DMA; +#if CONTROLLER_DMA + cfg.use_dma_tx = true; + cfg.use_dma_rx = true; + cfg.dma = MXC_DMA; #else - init.use_dma = false; + cfg.use_dma_rx = false; + cfg.use_dma_tx = false; + cfg.dma = MXC_DMA; #endif - retVal = MXC_SPI_Init_v2(&init); + retVal = MXC_SPI_Config(&cfg); if (retVal != E_NO_ERROR) { - printf("\nSPI INITIALIZATION ERROR\n"); + printf("\nSPI CONFIGURATION ERROR\n"); return retVal; } memset(rx_data, 0x0, DATA_LEN * sizeof(uint16_t)); // SPI Request (Callback) + mxc_spi_req_t req; + req.spi = SPI; + req.txData = (uint8_t *)tx_data; + req.txLen = DATA_LEN; + req.rxData = (uint8_t *)rx_data; + req.rxLen = DATA_LEN; + req.ssDeassert = 1; + req.completeCB = SPI_Callback; SPI_FLAG = 1; -#if BLOCKING - // Blocking SPI v2 Implementation is Interrupt driven. - NVIC_EnableIRQ(SPI_IRQ); - MXC_SPI_ControllerTransactionB(SPI, (uint8_t *)tx_data, DATA_LEN, (uint8_t *)rx_data, - DATA_LEN, 1, &target); +#if CONTROLLER_SYNC + MXC_SPI_ControllerTransaction(&req); #endif -#if NON_BLOCKING +#if CONTROLLER_ASYNC NVIC_EnableIRQ(SPI_IRQ); - MXC_SPI_ControllerTransaction(SPI, (uint8_t *)tx_data, DATA_LEN, (uint8_t *)rx_data, - DATA_LEN, 1, &target); + MXC_SPI_ControllerTransactionAsync(&req); while (SPI_FLAG == 1) {} #endif -#if DMA +#if CONTROLLER_DMA TX_DMA_CH = MXC_SPI_DMA_GetTXChannel(SPI); RX_DMA_CH = MXC_SPI_DMA_GetRXChannel(SPI); @@ -221,14 +209,14 @@ int main(void) MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(TX_DMA_CH), DMA_TX_IRQHandler); MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(RX_DMA_CH), DMA_RX_IRQHandler); - MXC_SPI_ControllerTransactionDMA(SPI, (uint8_t *)tx_data, DATA_LEN, (uint8_t *)rx_data, - DATA_LEN, 1, &target); + MXC_SPI_ControllerTransactionDMA(&req); while (SPI_FLAG == 1) {} #endif uint8_t bits = MXC_SPI_GetFrameSize(SPI); + // Reformat tx_data to match rx_data frame size. for (j = 0; j < DATA_LEN; j++) { if (bits <= 8) { if (j < (DATA_LEN / 2)) { @@ -254,6 +242,7 @@ int main(void) // Printf needs the Uart turned on since they share the same pins if (memcmp(rx_data, tx_data, sizeof(tx_data)) != 0) { printf("\n-->%2d Bits Transaction Failed\n", i); + LED_On(1); return E_COMM_ERR; } else { printf("-->%2d Bits Transaction Successful\n", i); @@ -268,5 +257,6 @@ int main(void) } printf("\nExample Complete.\n"); + LED_On(0); return E_NO_ERROR; } diff --git a/Examples/MAX78002/SPI/project.mk b/Examples/MAX78002/SPI/project.mk index a2fb5a9f960..675155fcc10 100644 --- a/Examples/MAX78002/SPI/project.mk +++ b/Examples/MAX78002/SPI/project.mk @@ -13,3 +13,5 @@ # Add your config here! +# Build SPI v2 library for example. +MXC_SPI_VERSION = v2 diff --git a/Examples/MAX78002/SPI_ControllerTarget/.cproject b/Examples/MAX78002/SPI_ControllerTarget/.cproject new file mode 100644 index 00000000000..204bc700394 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.cproject @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/MAX78002/SPI_ControllerTarget/.project b/Examples/MAX78002/SPI_ControllerTarget/.project new file mode 100644 index 00000000000..1b2fd1376e5 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.project @@ -0,0 +1,26 @@ + + + SPI_ControllerTarget + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/Examples/MAX78002/SPI_ControllerTarget/.settings/language.settings.xml b/Examples/MAX78002/SPI_ControllerTarget/.settings/language.settings.xml new file mode 100644 index 00000000000..d32c6f198c6 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.settings/language.settings.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.cdt.codan.core.prefs b/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 00000000000..59c0b37ba75 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,93 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.codan.checkers.errnoreturn=Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return\\")",implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused return value\\")"} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Nesting comments\\")"} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Line comments\\")"} +org.eclipse.cdt.codan.checkers.noreturn=Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return value\\")",implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Abstract class cannot be instantiated\\")"} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Ambiguous problem\\")"} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment in condition\\")"} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment to itself\\")"} +org.eclipse.cdt.codan.internal.checkers.CStyleCastProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.CStyleCastProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"C-Style cast instead of C++ cast\\")"} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No break at end of case\\")",no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false,enable_fallthrough_quickfix_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Catching by reference is recommended\\")",unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Circular inheritance\\")"} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class members should be properly initialized\\")",skip\=>true} +org.eclipse.cdt.codan.internal.checkers.CopyrightProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.CopyrightProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Lack of copyright information\\")",regex\=>".*Copyright.*"} +org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem=Error +org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid 'decltype(auto)' specifier\\")"} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Field cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Function cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.GotoStatementProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.GotoStatementProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Goto statement used\\")"} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid arguments\\")"} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid template argument\\")"} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Label statement not found\\")"} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Member declaration not found\\")"} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Method cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.MissCaseProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.MissCaseProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing cases in switch\\")"} +org.eclipse.cdt.codan.internal.checkers.MissDefaultProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.MissDefaultProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing default in switch\\")",defaultWithAllEnums\=>false} +org.eclipse.cdt.codan.internal.checkers.MissReferenceProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.MissReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing reference return value in assignment operator\\")"} +org.eclipse.cdt.codan.internal.checkers.MissSelfCheckProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.MissSelfCheckProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing self check in assignment operator\\")"} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Name convention for function\\")",pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class has a virtual method and non-virtual destructor\\")"} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid overload\\")"} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redeclaration\\")"} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redefinition\\")"} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Return with parenthesis\\")"} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Format String Vulnerability\\")"} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Statement has no effect\\")",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suggested parenthesis around expression\\")",paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suspicious semicolon\\")",else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Type cannot be resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused function declaration\\")",macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused static function\\")",macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused variable declaration in file scope\\")",macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.UsingInHeaderProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.UsingInHeaderProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Using directive in header\\")"} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Symbol is not resolved\\")"} +org.eclipse.cdt.codan.internal.checkers.VirtualMethodCallProblem=-Error +org.eclipse.cdt.codan.internal.checkers.VirtualMethodCallProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Virtual method call in constructor/destructor\\")"} +org.eclipse.cdt.qt.core.qtproblem=Warning +org.eclipse.cdt.qt.core.qtproblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_ON_FILE_OPEN\=>true,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>null} diff --git a/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.cdt.core.prefs b/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.cdt.core.prefs new file mode 100644 index 00000000000..63fc90a1a3b --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.cdt.core.prefs @@ -0,0 +1,15 @@ +eclipse.preferences.version=1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/BOARD/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/BOARD/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/BOARD/value=EvKit_V1 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/GCC_PREFIX/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/GCC_PREFIX/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/GCC_PREFIX/value=arm-none-eabi- +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/PROJECT/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/PROJECT/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/PROJECT/value=SPI_ControllerTarget +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/TARGET/delimiter=; +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/TARGET/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/TARGET/value=MAX78002 +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/append=true +environment/project/cdt.managedbuild.toolchain.gnu.cross.base.1028364529/appendContributed=true diff --git a/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.core.resources.prefs b/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..68a0304527f --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=windows-1252 diff --git a/Examples/MAX78002/SPI_ControllerTarget/.vscode/README.md b/Examples/MAX78002/SPI_ControllerTarget/.vscode/README.md new file mode 100644 index 00000000000..8b58b503892 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.vscode/README.md @@ -0,0 +1,422 @@ +# VSCode-Maxim + +_(If you're viewing this document from within Visual Studio Code you can press `CTRL+SHIFT+V` to open a Markdown preview window.)_ + +## Quick Links + +* [MSDK User Guide](https://analog-devices-msdk.github.io/msdk/USERGUIDE/) + * If it's not in the README, check the UG. + * If it's not in the UG, open a ticket! +* [VSCode-Maxim Github](https://github.com/Analog-Devices-MSDK/VSCode-Maxim) + +## Introduction + +VSCode-Maxim is a set of [Visual Studio Code](https://code.visualstudio.com/) project configurations and utilities for enabling embedded development for [Analog Device's MSDK](https://github.com/Analog-Devices-MSDK/msdk) and the [MAX32xxx/MAX78xxx microcontrollers](https://www.analog.com/en/product-category/microcontrollers.html). + +The following features are supported: + +* Code editing with intellisense down to the register level +* Code compilation with the ability to easily re-target a project for different microcontrollers and boards +* Flashing programs +* GUI and command-line debugging + +## Dependencies + +* [Visual Studio Code](https://code.visualstudio.com/) + * [C/C++ VSCode Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) + * [Cortex-Debug Extension](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) +* [Analog Devices MSDK](https://www.analog.com/en/design-center/evaluation-hardware-and-software/software/software-download?swpart=SFW0010820A) + +## Installation + +The steps below are also available in video form in "Understanding Artificial Intelligence Episode 8.5 - Visual Studio Code" [here](https://www.analog.com/en/education/education-library/videos/6313212752112.html). + +1. Download and install the Analog Devices MSDK for your OS from the links below. For more detailed instructions on installing the MSDK, see the [MSDK User Guide](https://analog-devices-msdk.github.io/msdk/USERGUIDE/) + * [Windows](https://www.analog.com/en/design-center/evaluation-hardware-and-software/software/software-download?swpart=SFW0010820A) + * [Linux (Ubuntu)](https://www.analog.com/en/design-center/evaluation-hardware-and-software/software/software-download?swpart=SFW0018720A) + * [MacOS](https://www.analog.com/en/design-center/evaluation-hardware-and-software/software/software-download?swpart=SFW0018610A) + +2. Run the installer executable, and ensure that "Visual Studio Code Support" is enabled for your installation. + + ![Selected Components](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/installer_components.JPG) + +3. Finish the MSDK installation, taking note of where the MSDK was installed. + +4. Download & install Visual Studio Code for your OS [here](https://code.visualstudio.com/Download). + +5. Launch Visual Studio Code. + +6. Install the Microsoft [C/C++ extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools). + +7. Install the [Cortex-Debug Extension](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) + +8. Use `CTRL + SHIFT + P` (or `COMMAND + SHIFT + P` on MacOS) to open the developer prompt. + +9. Type "open settings json" and select the "Preferences: Open Settings (JSON)" option (_not_ the "Preferences: Open _Default_ Settings (JSON)"). This will open your user settings.json file in VS Code's editor. + + ![Open Settings JSON Command](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/open_settings_json.jpg) + +10. Add the entries below into your user settings.json file. + + ```json + { + // There may be other settings up here... + + "MAXIM_PATH":"C:/MaximSDK", // Set this to the installed location of the Analog Devices MSDK. Only use forward slashes '/' when setting this path! + "update.mode": "manual", + "extensions.autoUpdate": false, + + // There may be other settings down here... + } + ``` + +11. Save your changes to the file with `CTRL + S` and restart VS Code. + +12. That's it! You're ready to start using Visual Studio Code to develop with Analog Devices MAX-series Microcontrollers. The MSDK examples come pre-populated with .vscode project folders, and the `Tools/VSCode-Maxim` folder of the MSDK contains documentation and templates. See [Usage](#usage) below for more details. + +## Usage + +This section covers basic usage of the VSCode-Maxim project files. For documentation on Visual Studio Code itself, please refer to the official docs [here](https://code.visualstudio.com/Docs). + +### Opening Projects + +Visual Studio Code is built around a "working directory" paradigm. The editor is always rooted in a working directory, and the main mechanism for changing that directory is `File -> Open Folder...`. + +![File -> Open Folder](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/file_openfolder.JPG) + +As a result, you'll notice that there is no "New Project" mechanism. A "project" in VS Code is simply a folder. It will look inside of the opened folder for a `.vscode` _sub_-folder to load project-specific settings from. + +A project that is configured for VS Code will have, at minimum, a .vscode sub-folder and a Makefile in its directory _(Note: You may need to enable viewing of hidden items in your file explorer to see the .vscode sub-folder)_. + +Ex: + +![Example Directory Contents](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/opening_projects_2.jpg) + +### Where to Find Projects + +The [Examples](https://github.com/Analog-Devices-MSDK/msdk/tree/main/Examples) in the MSDK come with with pre-configured .vscode project folders. These projects can be opened "out of the box", but it's good practice to copy example folders _outside_ of the MSDK so that the original copies are kept as clean references. The examples can be freely moved to any location _without a space in its path_. + +Additionally, empty project templates and a drag-and-drop folder for "injecting" a VSCode-Maxim project can be found under `Tools/VSCode-Maxim` in the MSDK installation. + +### Build Tasks + +Once a project is opened 4 available build tasks will become available via `Terminal > Run Build task...` or the shortcut `Ctrl+Shift+B`. These tasks are configured by the `.vscode/task.json` file. + +![Build Tasks Image](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/buildtasks.JPG) + +#### Build + +* Compiles the code with a `make all` command. +* Additional options are passed into Make on the command-line based on the project's settings.json file. +* The `./build` directory will be created and will contain the output binary, as well as all intermediary object files. + +#### Clean + +* Cleans the build output, removing the `./build` directory and all of its contents. + +#### Clean-Periph + +* This task is the same as 'clean', but it also removes the build output for the MSDK's peripheral drivers. +* Use this if you would like to recompile the peripheral drivers from source on the next build. + +#### Flash + +* Launching this task automatically runs the `Build` task first. Then, it flashes the output binary to the microcontroller. +* It uses the GDB `load` and `compare-sections` commands, and handles launching an OpenOCD internally via a pipe connection. +* The flashed program will be halted until the microcontroller is reset, power cycled, or a debugger is connected. +* A debugger must be connected correctly to use this task. Refer to the datasheet of your microcontroller's evaluation board for instructions. + +#### Flash & Run + +* This is the same as the `Flash` task, but it also will launch execution of the program once flashing is complete. + +#### Erase Flash + +* Completely erases all of the application code in the flash memory bank. +* Once complete, the target microcontroller will be effectively "blank". +* This can be useful for recovering from Low-Power (LP) lockouts, bad firmware, etc. + +### Debugging + +![Debug Window](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/debugger.JPG) + +Debugging is enabled by Visual Studio Code's integrated debugger. Launch configurations can be found in the `.vscode/launch.json` file. + +* Note: **Flashing does not happen automatically when launching the debugger.** Run the "Flash" [build task](#build-tasks) for your program _before_ debugging. + +#### Debugger Limitations + +In general, the MAX-series microcontrollers have the following debugger limitations at the hardware level: + +* The debugger can not be connected _while_ the device is in reset. + +* The device can not be debugged while the device is in Sleep, Low Power Mode, Micro Power Mode, Standby, Backup, or Shutdown mode. These modes shut down the SWD clock. + +* These limitations can sometimes make the device difficult or impossible to connect to if firmware has locked out the debugger. In such cases, the ["Erase Flash"](#erase-flash) task can be used to recover the part. + +#### Launching the Debugger + +1. Attach your debugger to the SWD port on the target microcontroller. (Refer to the datasheet of your evaluation board for instructions on connecting a debugger) + +2. Flash the program to the microcontroller with the "Flash" [Build Task](#build-tasks). **Flashing does not happen automatically when launching the debugger.** + +3. Launch the debugger with `Run > Start Debugging`, with the shortcut `F5`, or via the `Run and Debug` window (Ctrl + Shift + D) and the green "launch" arrow. + + ![Debug Tab](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/debugger_window.JPG) + +4. The debugger will launch a GDB client & OpenOCD server, reset the microcontroller, and should break on entry into `main`. + + ![Debugger Break on Main](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/debugger_breakmain.JPG) + +#### Using the Debugger + +* For full usage details, please refer to the [official VS Code debugger documentation](https://code.visualstudio.com/docs/editor/debugging). + +The main interface for the debugger is the debugger control bar: + +![Debugger Control Bar Image](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/debugger_bar.JPG) + +`Continue | Step Over | Step Into | Step Out | Restart | Stop` + +Breakpoints can be set by clicking in the space next to the line number in a source code file. A red dot indicates a line to break on. Breakpoints can be removed by clicking on them again. Ex: + +![Breakpoint](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/breakpoint.JPG) + +## Project Configuration + +### Project Settings + +`.vscode/settings.json` is the main project configuration file. Values set here are parsed into the other .json config files. + +**When a change is made to this file, VS Code should be reloaded with CTRL+SHIFT+P -> Reload Window (or alternatively restarted completely) to force a re-parse.** + +![Reload Window](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/reload_window.JPG) + +The default project configuration should work for most use cases as long as `"target"` and `"board"` are set correctly. + +Any field from `settings.json` can be referenced from any other config file (including itself) with `"${config:[fieldname]}"` + +The following configuration options are available: + +### Basic Config Options + +#### `"target"` + +* This sets the target microcontroller for the project. +* It sets the `TARGET` [Build Configuration](#build-configuration) variable. +* Supported values: + * `"MAX32520"` + * `"MAX32570"` + * `"MAX32650"` + * `"MAX32655"` + * `"MAX32660"` + * `"MAX32662"` + * `"MAX32665"` (for MAX32665-MAX32668) + * `"MAX32670"` + * `"MAX32672"` + * `"MAX32675"` + * `"MAX32680"` + * `"MAX32690"` + * `"MAX78000"` + * `"MAX78002"` + +#### `"board"` + +* This sets the target board for the project (ie. Evaluation Kit, Feather board, etc.) +* Supported values: + * ... can be found in the `Libraries/Boards` folder of the MSDK + * For example, the supported options for the MAX78000 are `"EvKit_V1"`, `"FTHR_RevA"`, and `"MAXREFDES178"`. + + ![MAX78000 Boards](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/main/img/78000_boards.JPG) + +### Advanced Config Options + +#### `"MAXIM_PATH"` + +* This option must point to the root installation directory of the MSDK. +* It should be placed in the _global_ user settings.json file during first-time VSCode-Maxim setup. See [Installation](#installation). + +#### `"terminal.integrated.env.[platform]:Path"` + +* This prepends the location of the MSDK toolchain binaries to the system `Path` used by VSCode's integrated terminal. +* The Path is not sanitized by default, which means that the terminal inherits the system path. +* Don't touch unless you know what you're doing :) + +#### `"project_name"` + +* Sets the name of project. This is used in other config options such as `program_file`. +* Default value: `"${workspaceFolderBasename}"` + +#### `"program_file"` + +* Sets the name of the file to flash and debug. This is provided in case it's needed, but for most use cases should be left at its default. +* File extension must be included. +* Default value: `"${config:project_name}.elf"` + +#### `"symbol_file"` + +* Sets the name of the file that GDB will load debug symbols from. +* File extension must be included. +* Default value: `"${config:program_file}"` + +#### `"M4_OCD_interface_file"` + +* Sets the OpenOCD interface file to use to connect to the Arm M4 core. This should match the debugger being used for the M4 core. +* The `MaximSDK/Tools/OpenOCD/scripts/interface` folder is searched for the file specified by this setting. +* `.cfg` file extension must be included. +* Default value: `"cmsis-dap.cfg"` + +#### `"M4_OCD_target_file"` + +* Sets the OpenOCD target file to use for the Arm M4 core. This should match the target microcontroller. +* `.cfg` file extension must be included. +* The `MaximSDK/Tools/OpenOCD/scripts/target` folder is searched for the file specified by this setting. +* Default value: `"${config:target}.cfg"` + +#### `"RV_OCD_interface_file"` + +* Sets the OpenOCD interface file to use to connect to the RISC-V core. This should match the debugger being used for the RISC-V core. +* The `MaximSDK/Tools/OpenOCD/scripts/interface` folder is searched for the file specified by this setting. +* `.cfg` file extension must be included. +* Default value: `"ftdi/olimex-arm-usb-ocd-h.cfg"` + +#### `"RV_OCD_target_file"` + +* Sets the OpenOCD target file to use for the RISC-V core. +* The `MaximSDK/Tools/OpenOCD/scripts/target` folder is searched for the file specified by this setting. +* `.cfg` file extension must be included. +* Default value: `"${config:target}_riscv.cfg"` + +#### `"v_Arm_GCC"` + +* Sets the version of the Arm Embedded GCC to use, including toolchain binaries and the standard library version. +* This gets parsed into `ARM_GCC_path`. +* Default value: `"10.3"` + +#### `"v_xPack_GCC"` + +* Sets the version of the xPack RISC-V GCC to use. +* This gets parsed into `xPack_GCC_path`. +* Default value: `"10.2.0-1.2"` + +#### `"OCD_path"` + +* Where to find the OpenOCD. +* Default value: `"${config:MAXIM_PATH}/Tools/OpenOCD"` + +#### `"ARM_GCC_path"` + +* Where to find the Arm Embedded GCC Toolchain. +* Default value: `"${config:MAXIM_PATH}/Tools/GNUTools/${config:v_Arm_GCC}"` + +#### `"xPack_GCC_path"` + +* Where to find the RISC-V GCC Toolchain. +* Default value: `"${config:MAXIM_PATH}/Tools/xPack/riscv-none-embed-gcc/${config:v_xPack_GCC}"` + +#### `"Make_path"` + +* Where to find Make binaries (only used on Windows) +* Default value: `"${config:MAXIM_PATH}/Tools/MSYS2/usr/bin"` + +#### `"C_Cpp.default.includePath"` + +* Which paths to search to find header (.h) files. +* Does not recursively search by default. To recursively search, use `/**`. + +#### `"C_Cpp.default.browse.path"` + +* Which paths to search to find source (.c) files. +* Does not recursively search by default. To recursively search, use `/**`. + +#### `"C_Cpp.default.defines"` + +* Sets the compiler definitions to use for the intellisense engine. +* Most definitions should be defined in header files, but if a definition is missing it can be entered here to get the intellisense engine to recognize it. + +### Setting Search Paths for Intellisense + +VS Code's intellisense engine must be told where to find the header files for your source code. By default, the MSDK's peripheral drivers, the C standard libraries, and all of the sub-directories of the workspace will be searched for header files to use with Intellisense. If VS Code throws an error on an `#include` statement (and the file exists), then a search path is most likely missing. + +To add additional search paths : + +1. Open the `.vscode/settings.json` file. + +2. Add the include path(s) to the `C_Cpp.default.includePath` list. The paths set here should contain header files, and will be searched by the Intellisense engine and when using "Go to Declaration" in the editor. + +3. Add the path(s) to any relevant implementation files to the `C_Cpp.default.browse.path` list. This list contains the paths that will be searched when using "Go to Definition". + +## Build Configuration + +A project's build system is managed by two files found in the project's root directory. These files are used alongside the [GNU Make](https://www.gnu.org/software/make/) program (which is a part of the MSDK toolchain) to locate and build a project's source code for the correct microcontroller. + +* `Makefile` +* `project.mk` + +![Files are located in the root directory](https://raw.githubusercontent.com/Analog-Devices-MSDK/VSCode-Maxim/65af7c61800c7039956f3c1971ffd7915008668d/img/projectmk.JPG) + +When the command... + +```shell +make +``` + +... is run, the program `make` will load settings from these two files. Then, it will use them to build the project's source code. VSCode-Maxim is a "wrapper" around this Makefile system. + +**See the [MSDK User Guide](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system) for full documentation on how to configure the build system.** + +## Project Creation + +### Option 1. Copying a Pre-Made Project + +Copying a pre-made example project is a great way to get rolling quickly, and is currently the recommended method for creating new projects. + +The release package for this project (Located at Tools/VSCode-Maxim in the Analog Devices MSDK) contains a `New_Project` folder designed for such purposes. Additionally, any of the VS Code-enabled Example projects can be copied from the MSDK. + +1. Copy the existing project folder to an accessible location. This will be the location of your new project. + +2. (Optional) Rename the folder. For example, I might rename the folder to `MyProject`. + +3. Open the project in VS Code (`File -> Open Folder...`) + +4. Set your target microcontroller and board correctly. See [Basic Config Options](#basic-config-options) + +5. `CTRL+SHIFT+P -> Reload Window` to re-parse the project settings. + +6. That's it! The existing project is ready to build, debug, and modify. + +### Option 2 - Injecting + +VSCode-Maxim releases provide the `Inject` folder for "injecting" into an existing folder. If you want to start from scratch or use the project files with existing source code, take this option. + +1. Create your project folder if necessary. For example, I might create a new project in a workspace folder with the path: `C:\Users\Jake.Carter\workspace\MyNewProject`. + +2. Copy the **contents** of the `Inject` folder into the project folder from step 1. The contents to copy include a `.vscode` folder, a `Makefile`, and a `project.mk` file. For this example, the contents of the 'MyProject' folder would be the following: + + ```shell + C:\Users\Jake.Carter\workspace\MyNewProject + |- .vscode + |- Makefile + |- project.mk + ``` + +3. Open the project in VS Code (`File -> Open Folder...`) + +4. Set your target microcontroller correctly. See [Basic Config Options](#basic-config-options). + +5. `CTRL+SHIFT+P -> Reload Window` to re-parse the project settings. + +6. Configure the [build system](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system) for use with any pre-existing source code. + +7. That's it! Your new empty project can now be opened with `File > Open Folder` from within VS Code. + +## Issue Tracker + +Bug reports, feature requests, and contributions are welcome via the [issues](https://github.com/Analog-Devices-MSDK/VSCode-Maxim/issues) tracker on Github. + +New issues should contain _at minimum_ the following information: + +* Visual Studio Code version #s (see `Help -> About`) +* C/C++ Extension version # +* Target microcontroller and evaluation platform +* The projects `.vscode` folder and `Makefile` (where applicable). Standard compression formats such as `.zip`, `.rar`, `.tar.gz`, etc. are all acceptable. diff --git a/Examples/MAX78002/SPI_ControllerTarget/.vscode/c_cpp_properties.json b/Examples/MAX78002/SPI_ControllerTarget/.vscode/c_cpp_properties.json new file mode 100644 index 00000000000..dfbed47b581 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.vscode/c_cpp_properties.json @@ -0,0 +1,53 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${default}" + ], + "defines": [ + "${default}" + ], + "intelliSenseMode": "gcc-arm", + "compilerPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gcc.exe", + "browse": { + "path": [ + "${default}" + ] + } + }, + { + "name": "Linux", + "includePath": [ + "${default}" + ], + "defines": [ + "${default}" + ], + "intelliSenseMode": "gcc-arm", + "compilerPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gcc", + "browse": { + "path": [ + "${default}" + ] + } + }, + { + "name": "Mac", + "includePath": [ + "${default}" + ], + "defines": [ + "${default}" + ], + "intelliSenseMode": "gcc-arm", + "compilerPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gcc", + "browse": { + "path": [ + "${default}" + ] + } + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Examples/MAX78002/SPI_ControllerTarget/.vscode/flash.gdb b/Examples/MAX78002/SPI_ControllerTarget/.vscode/flash.gdb new file mode 100644 index 00000000000..fc627ae86a3 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.vscode/flash.gdb @@ -0,0 +1,15 @@ +define flash_m4 + set architecture armv7e-m + target remote | openocd -c "gdb_port pipe;log_output flash.log" -s $arg0/scripts -f interface/$arg1 -f target/$arg2 -c "init; reset halt" + load + compare-sections + monitor reset halt +end + +define flash_m4_run + set architecture armv7e-m + target remote | openocd -c "gdb_port pipe;log_output flash.log" -s $arg0/scripts -f interface/$arg1 -f target/$arg2 -c "init; reset halt" + load + compare-sections + monitor resume +end \ No newline at end of file diff --git a/Examples/MAX78002/SPI_ControllerTarget/.vscode/launch.json b/Examples/MAX78002/SPI_ControllerTarget/.vscode/launch.json new file mode 100644 index 00000000000..af0d6f650c7 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.vscode/launch.json @@ -0,0 +1,133 @@ +{ + "configurations": [ + { + "name": "Debug Arm (Cortex-debug)", + "cwd":"${workspaceRoot}", + "executable": "${workspaceFolder}/build/${config:program_file}", + "loadFiles": ["${workspaceFolder}/build/${config:program_file}"], + "symbolFiles": [{ + "file": "${workspaceFolder}/build/${config:symbol_file}" + }], + "request": "launch", + "type": "cortex-debug", + "servertype": "openocd", + "linux": { + "gdbPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gdb", + "serverpath": "${config:OCD_path}/openocd", + }, + "windows": { + "gdbPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gdb.exe", + "serverpath": "${config:OCD_path}/openocd.exe", + }, + "osx": { + "gdbPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gdb", + "serverpath": "${config:OCD_path}/openocd", + }, + "searchDir": ["${config:OCD_path}/scripts"], + "configFiles": ["interface/${config:M4_OCD_interface_file}", "target/${config:M4_OCD_target_file}"], + "interface": "swd", + "runToEntryPoint": "main", + "svdFile": "${config:MAXIM_PATH}/Libraries/CMSIS/Device/Maxim/${config:target}/Include/${config:target}.svd" + }, + { + "name": "GDB (Arm M4)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/${config:program_file}", + "args": [], + "stopAtEntry": true, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "linux": { + "miDebuggerPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gdb", + "debugServerPath": "${config:OCD_path}/openocd", + }, + "windows": { + "miDebuggerPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gdb.exe", + "debugServerPath": "${config:OCD_path}/openocd.exe", + }, + "osx": { + "miDebuggerPath": "${config:ARM_GCC_path}/bin/arm-none-eabi-gdb", + "debugServerPath": "${config:OCD_path}/bin/openocd", + }, + "logging": { + "exceptions": true, + "trace": false, + "traceResponse": false, + "engineLogging": false + }, + "miDebuggerServerAddress": "localhost:3333", + "debugServerArgs": "-s ${config:OCD_path}/scripts -f interface/${config:M4_OCD_interface_file} -f target/${config:M4_OCD_target_file} -c \"init; reset halt\"", + "serverStarted": "Info : Listening on port 3333 for gdb connections", + "filterStderr": true, + "targetArchitecture": "arm", + "customLaunchSetupCommands": [ + {"text":"-list-features"} + ], + "setupCommands": [ + { "text":"set logging overwrite on"}, + { "text":"set logging file debug-arm.log"}, + { "text":"set logging on"}, + { "text":"cd ${workspaceFolder}" }, + { "text":"exec-file build/${config:program_file}" }, + { "text":"symbol-file build/${config:symbol_file}" }, + { "text":"target remote localhost:3333" }, + { "text":"monitor reset halt" }, + { "text":"set $pc=Reset_Handler"}, + { "text":"b main" } + ] + }, + { + "name": "GDB (RISC-V)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/buildrv/${config:program_file}", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "linux": { + "miDebuggerPath": "${config:xPack_GCC_path}/bin/riscv-none-embed-gdb", + "debugServerPath": "${config:OCD_path}/openocd", + }, + "windows": { + "miDebuggerPath": "${config:xPack_GCC_path}/bin/riscv-none-embed-gdb.exe", + "debugServerPath": "${config:OCD_path}/openocd.exe", + }, + "osx": { + "miDebuggerPath": "${config:xPack_GCC_path}/bin/riscv-none-embed-gdb", + "debugServerPath": "${config:OCD_path}/bin/openocd", + }, + "logging": { + "exceptions": true, + "trace": false, + "traceResponse": false, + "engineLogging": false + }, + "miDebuggerServerAddress": "localhost:3334", + "debugServerArgs": "-c \"gdb_port 3334\" -s ${config:OCD_path}/scripts -f interface/${config:RV_OCD_interface_file} -f target/${config:RV_OCD_target_file}", + "serverStarted": "Info : Listening on port 3334 for gdb connections", + "filterStderr": true, + "customLaunchSetupCommands": [ + {"text":"-list-features"} + ], + "targetArchitecture": "arm", + "setupCommands": [ + { "text":"set logging overwrite on"}, + { "text":"set logging file debug-riscv.log"}, + { "text":"set logging on"}, + { "text":"cd ${workspaceFolder}" }, + { "text": "set architecture riscv:rv32", "ignoreFailures": false }, + { "text":"exec-file build/${config:program_file}", "ignoreFailures": false }, + { "text":"symbol-file buildrv/${config:symbol_file}", "ignoreFailures": false }, + { "text":"target remote localhost:3334" }, + { "text":"b main" }, + { "text": "set $pc=Reset_Handler","ignoreFailures": false } + ] + } + ] +} \ No newline at end of file diff --git a/Examples/MAX78002/SPI_ControllerTarget/.vscode/settings.json b/Examples/MAX78002/SPI_ControllerTarget/.vscode/settings.json new file mode 100644 index 00000000000..cfbc63cac35 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.vscode/settings.json @@ -0,0 +1,74 @@ +{ + "terminal.integrated.env.windows": { + "Path":"${config:OCD_path};${config:ARM_GCC_path}/bin;${config:xPack_GCC_path}/bin;${config:Make_path};${env:PATH}", + "MAXIM_PATH":"${config:MAXIM_PATH}" + }, + "terminal.integrated.defaultProfile.windows": "Command Prompt", + + "terminal.integrated.env.linux": { + "PATH":"${config:OCD_path}:${config:ARM_GCC_path}/bin:${config:xPack_GCC_path}/bin:${env:PATH}", + "MAXIM_PATH":"${config:MAXIM_PATH}" + }, + "terminal.integrated.env.osx": { + "PATH":"${config:OCD_path}/bin:${config:ARM_GCC_path}/bin:${config:xPack_GCC_path}/bin:${env:PATH}", + "MAXIM_PATH":"${config:MAXIM_PATH}" + }, + + "target":"MAX78002", + "board":"EvKit_V1", + + "project_name":"${workspaceFolderBasename}", + + "program_file":"${config:project_name}.elf", + "symbol_file":"${config:program_file}", + + "M4_OCD_interface_file":"cmsis-dap.cfg", + "M4_OCD_target_file":"max78002.cfg", + "RV_OCD_interface_file":"ftdi/olimex-arm-usb-ocd-h.cfg", + "RV_OCD_target_file":"${config:target}_riscv.cfg", + + "v_Arm_GCC":"10.3", + "v_xPack_GCC":"12.2.0-3.1", + + "OCD_path":"${config:MAXIM_PATH}/Tools/OpenOCD", + "ARM_GCC_path":"${config:MAXIM_PATH}/Tools/GNUTools/${config:v_Arm_GCC}", + "xPack_GCC_path":"${config:MAXIM_PATH}/Tools/xPack/riscv-none-elf-gcc/${config:v_xPack_GCC}", + "Make_path":"${config:MAXIM_PATH}/Tools/MSYS2/usr/bin", + + "C_Cpp.default.includePath": [ + "${workspaceFolder}", + "${workspaceFolder}/**", + "${config:MAXIM_PATH}/Libraries/Boards/${config:target}/${config:board}/Include", + "${config:MAXIM_PATH}/Libraries/CMSIS/Device/Maxim/${config:target}/Include", + "${config:MAXIM_PATH}/Libraries/CMSIS/Include", + "${config:ARM_GCC_path}/arm-none-eabi/include", + "${config:ARM_GCC_path}/lib/gcc/arm-none-eabi/${config:v_Arm_GCC}/include", + "${config:MAXIM_PATH}/Libraries/PeriphDrivers/Include/${config:target}", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/Camera", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/Display", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/ExtMemory", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/LED", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/PMIC", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/PushButton", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/Touchscreen" + ], + "C_Cpp.default.browse.path": [ + "${workspaceFolder}", + "${config:MAXIM_PATH}/Libraries/Boards/${config:target}/${config:board}/Source", + "${config:MAXIM_PATH}/Libraries/PeriphDrivers/Source", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/Camera", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/Display", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/LED", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/PMIC", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/PushButton", + "${config:MAXIM_PATH}/Libraries/MiscDrivers/Touchscreen", + "${config:MAXIM_PATH}/Libraries/MiscDrivers" + ], + "C_Cpp.default.defines": [ + + ], + "C_Cpp.default.forcedInclude": [ + "${workspaceFolder}/build/project_defines.h" + ] +} + diff --git a/Examples/MAX78002/SPI_ControllerTarget/.vscode/tasks.json b/Examples/MAX78002/SPI_ControllerTarget/.vscode/tasks.json new file mode 100644 index 00000000000..e95445e2b3e --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/.vscode/tasks.json @@ -0,0 +1,115 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "make -r -j 8 --output-sync=target --no-print-directory TARGET=${config:target} BOARD=${config:board} MAXIM_PATH=${config:MAXIM_PATH} MAKE=make PROJECT=${config:project_name}", + "osx":{ + "command": "source ~/.zshrc && make -r -j 8 --output-sync=target --no-print-directory TARGET=${config:target} BOARD=${config:board} MAXIM_PATH=${config:MAXIM_PATH} MAKE=make PROJECT=${config:project_name}" + }, + "group": "build", + "problemMatcher": [] + }, + { + "label": "clean", + "type": "shell", + "command": "make -j 8 clean --output-sync=target --no-print-directory TARGET=${config:target} BOARD=${config:board} MAXIM_PATH=${config:MAXIM_PATH} MAKE=make PROJECT=${config:project_name}", + "osx":{ + "command": "source ~/.zshrc && make -j 8 clean --output-sync=target --no-print-directory TARGET=${config:target} BOARD=${config:board} MAXIM_PATH=${config:MAXIM_PATH} MAKE=make PROJECT=${config:project_name}" + }, + "group": "build", + "problemMatcher": [] + }, + { + "label": "clean-periph", + "type": "shell", + "command": "make -j 8 distclean --output-sync=target --no-print-directory TARGET=${config:target} BOARD=${config:board} MAXIM_PATH=${config:MAXIM_PATH} MAKE=make PROJECT=${config:project_name}", + "osx":{ + "command": "source ~/.zshrc && make -j 8 distclean --output-sync=target --no-print-directory TARGET=${config:target} BOARD=${config:board} MAXIM_PATH=${config:MAXIM_PATH} MAKE=make PROJECT=${config:project_name}" + }, + "group": "build", + "problemMatcher": [] + }, + { + "label": "flash", + "type": "shell", + "command": "arm-none-eabi-gdb", + "args": [ + "--cd=\"${workspaceFolder}\"", + "--se=\"build/${config:program_file}\"", + "--symbols=build/${config:symbol_file}", + "-x=\"${workspaceFolder}/.vscode/flash.gdb\"", + "--ex=\"flash_m4 ${config:OCD_path} ${config:M4_OCD_interface_file} ${config:M4_OCD_target_file}\"", + "--batch" + ], + "group": "build", + "problemMatcher": [], + "dependsOn":["build"] + }, + { + "label": "flash & run", + "type": "shell", + "command": "arm-none-eabi-gdb", + "args": [ + "--cd=\"${workspaceFolder}\"", + "--se=\"build/${config:program_file}\"", + "--symbols=build/${config:symbol_file}", + "-x=\"${workspaceFolder}/.vscode/flash.gdb\"", + "--ex=\"flash_m4_run ${config:OCD_path} ${config:M4_OCD_interface_file} ${config:M4_OCD_target_file}\"", + "--batch" + ], + "group": "build", + "problemMatcher": [], + "dependsOn":["build"] + }, + { + "label": "erase flash", + "type": "shell", + "command": "openocd", + "args": [ + "-s", "${config:OCD_path}/scripts", + "-f", "interface/${config:M4_OCD_interface_file}", + "-f", "target/${config:M4_OCD_target_file}", + "-c", "\"init; reset halt; max32xxx mass_erase 0;\"", + "-c", "exit" + ], + "group":"build", + "problemMatcher": [], + "dependsOn":[] + }, + { + "label": "openocd (m4)", + "type": "shell", + "command": "openocd", + "args": [ + "-s", + "${config:OCD_path}/scripts", + "-f", + "interface/${config:M4_OCD_interface_file}", + "-f", + "target/${config:M4_OCD_target_file}", + "-c", + "\"init; reset halt\"" + ], + "problemMatcher": [], + "dependsOn":[] + }, + { + "label": "gdb (m4)", + "type": "shell", + "command": "arm-none-eabi-gdb", + "args": [ + "--ex=\"cd ${workspaceFolder}\"", + "--se=\"build/${config:program_file}\"", + "--symbols=build/${config:symbol_file}", + "--ex=\"target remote localhost:3333\"", + "--ex=\"monitor reset halt\"", + "--ex=\"b main\"", + "--ex=\"c\"" + ], + "problemMatcher": [], + "dependsOn":[] + }, + ] +} \ No newline at end of file diff --git a/Examples/MAX78002/SPI_ControllerTarget/Makefile b/Examples/MAX78002/SPI_ControllerTarget/Makefile new file mode 100644 index 00000000000..80ac4541473 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/Makefile @@ -0,0 +1,395 @@ +################################################################################ + # Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. + # + # Permission is hereby granted, free of charge, to any person obtaining a + # copy of this software and associated documentation files (the "Software"), + # to deal in the Software without restriction, including without limitation + # the rights to use, copy, modify, merge, publish, distribute, sublicense, + # and/or sell copies of the Software, and to permit persons to whom the + # Software is furnished to do so, subject to the following conditions: + # + # The above copyright notice and this permission notice shall be included + # in all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + # IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + # OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + # OTHER DEALINGS IN THE SOFTWARE. + # + # Except as contained in this notice, the name of Maxim Integrated + # Products, Inc. shall not be used except as stated in the Maxim Integrated + # Products, Inc. Branding Policy. + # + # The mere transfer of this software does not imply any licenses + # of trade secrets, proprietary technology, copyrights, patents, + # trademarks, maskwork rights, or any other form of intellectual + # property whatsoever. Maxim Integrated Products, Inc. retains all + # ownership rights. + # +############################################################################### + +# ** Readme! ** +# Don't edit this file! This is the core Makefile for a MaximSDK +# project. The available configuration options can be overridden +# in "project.mk", on the command-line, or with system environment +# variables. + +# See https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system +# for more detailed instructions on how to use this system. + +# The detailed instructions mentioned above are easier to read than +# this file, but the comments found in this file also outline the +# available configuration variables. This file is organized into +# sub-sections, some of which expose config variables. + + +# ******************************************************************************* +# Set the target microcontroller and board to compile for. + +# Every TARGET microcontroller has some Board Support Packages (BSPs) that are +# available for it under the MaximSDK/Libraries/Boards/TARGET folder. The BSP +# that gets selected is MaximSDK/Libraries/Boards/TARGET/BOARD. + +# Configuration Variables: +# - TARGET : Override the default target microcontroller. Ex: TARGET=MAX78000 +# - BOARD : Override the default BSP (case sensitive). Ex: BOARD=EvKit_V1, BOARD=FTHR_RevA + + +ifeq "$(TARGET)" "" +# Default target microcontroller +TARGET := MAX78002 +TARGET_UC := MAX78002 +TARGET_LC := max78002 +else +# "TARGET" has been overridden in the environment or on the command-line. +# We need to calculate an upper and lowercase version of the part number, +# because paths on Linux and MacOS are case-sensitive. +TARGET_UC := $(subst m,M,$(subst a,A,$(subst x,X,$(TARGET)))) +TARGET_LC := $(subst M,m,$(subst A,a,$(subst X,x,$(TARGET)))) +endif + +# Default board. +BOARD ?= EvKit_V1 + +# ******************************************************************************* +# Locate the MaximSDK + +# This Makefile needs to know where to find the MaximSDK, and the MAXIM_PATH variable +# should point to the root directory of the MaximSDK installation. Setting this manually +# is usually only required if you're working on the command-line. + +# If MAXIM_PATH is not specified, we assume the project still lives inside of the MaximSDK +# and move up from this project's original location. + +# Configuration Variables: +# - MAXIM_PATH : Tell this Makefile where to find the MaximSDK. Ex: MAXIM_PATH=C:/MaximSDK + + +ifneq "$(MAXIM_PATH)" "" +# Sanitize MAXIM_PATH for backslashes +MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) +# Locate some other useful paths... +LIBS_DIR := $(abspath $(MAXIM_PATH)/Libraries) +CMSIS_ROOT := $(LIBS_DIR)/CMSIS +endif + +# ******************************************************************************* +# Include project Makefile. We do this after formulating TARGET, BOARD, and MAXIM_PATH +# in case project.mk needs to reference those values. However, we also include +# this as early as possible in the Makefile so that it can append to or override +# the variables below. + + +PROJECTMK ?= $(abspath ./project.mk) +include $(PROJECTMK) +$(info Loaded project.mk) +# PROJECTMK is also used by implicit rules and other libraries to add project.mk as a watch file + +# ******************************************************************************* +# Final path sanitization and re-calculation. No options here. + +ifeq "$(MAXIM_PATH)" "" +# MAXIM_PATH is still not defined... +DEPTH := ../../../ +MAXIM_PATH := $(abspath $(DEPTH)) +$(warning Warning: MAXIM_PATH is not set! Set MAXIM_PATH in your environment or in project.mk to clear this warning.) +$(warning Warning: Attempting to use $(MAXIM_PATH) calculated from relative path) +else +# Sanitize MAXIM_PATH for backslashes +MAXIM_PATH := $(subst \,/,$(MAXIM_PATH)) +endif + +# Final recalculation of LIBS_DIR/CMSIS_ROOT +LIBS_DIR := $(abspath $(MAXIM_PATH)/Libraries) +CMSIS_ROOT := $(LIBS_DIR)/CMSIS + +# One final UC/LC check in case user set TARGET in project.mk +TARGET_UC := $(subst m,M,$(subst a,A,$(subst x,X,$(TARGET)))) +TARGET_LC := $(subst M,m,$(subst A,a,$(subst X,x,$(TARGET)))) + +export TARGET +export TARGET_UC +export TARGET_LC +export CMSIS_ROOT +# TODO: Remove dependency on exports for these variables. + +# ******************************************************************************* +# Set up search paths, and auto-detect all source code on those paths. + +# The following paths are searched by default, where "./" is the project directory. +# ./ +# |- *.h +# |- *.c +# |-include (optional) +# |- *.h +# |-src (optional) +# |- *.c + +# Configuration Variables: +# - VPATH : Tell this Makefile to search additional locations for source (.c) files. +# You should use the "+=" operator with this option. +# Ex: VPATH += your/new/path +# - IPATH : Tell this Makefile to search additional locations for header (.h) files. +# You should use the "+=" operator with this option. +# Ex: VPATH += your/new/path +# - SRCS : Tell this Makefile to explicitly add a source (.c) file to the build. +# This is really only useful if you want to add a source file that isn't +# on any VPATH, in which case you can add the full path to the file here. +# You should use the "+=" operator with this option. +# Ex: SRCS += your/specific/source/file.c +# - AUTOSEARCH : Set whether this Makefile should automatically detect .c files on +# VPATH and add them to the build. This is enabled by default. Set +# to 0 to disable. If autosearch is disabled, source files must be +# manually added to SRCS. +# Ex: AUTOSEARCH = 0 + + +# Where to find source files for this project. +VPATH += . +VPATH += src +VPATH := $(VPATH) + +# Where to find header files for this project +IPATH += . +IPATH += include +IPATH := $(IPATH) + +AUTOSEARCH ?= 1 +ifeq ($(AUTOSEARCH), 1) +# Auto-detect all C/C++ source files on VPATH +SRCS += $(wildcard $(addsuffix /*.c, $(VPATH))) +SRCS += $(wildcard $(addsuffix /*.cpp, $(VPATH))) +endif + +# Collapse SRCS before passing them on to the next stage +SRCS := $(SRCS) + +# ******************************************************************************* +# Set the output filename + +# Configuration Variables: +# - PROJECT : Override the default output filename. Ex: PROJECT=MyProject + + +# The default value creates a file named after the target micro. Ex: MAX78000.elf +PROJECT ?= $(TARGET_LC) + +# ******************************************************************************* +# Compiler options + +# Configuration Variables: +# - DEBUG : Set DEBUG=1 to build explicitly for debugging. This adds some additional +# symbols and sets -Og as the default optimization level. +# - MXC_OPTIMIZE_CFLAGS : Override the default compiler optimization level. +# Ex: MXC_OPTIMIZE_CFLAGS = -O2 +# - PROJ_CFLAGS : Add additional compiler flags to the build. +# You should use the "+=" operator with this option. +# Ex: PROJ_CFLAGS += -Wextra +# - MFLOAT_ABI : Set the floating point acceleration level. +# The only options are "hard", "soft", or "softfp". +# Ex: MFLOAT_ABI = hard +# - LINKERFILE : Override the default linkerfile. +# Ex: LINKERFILE = customlinkerfile.ld +# - LINKERPATH : Override the default search location for $(LINKERFILE) +# The default search location is $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/GCC +# If $(LINKERFILE) cannot be found at this path, then the root project +# directory will be used as a fallback. + +# Select 'GCC' or 'IAR' compiler +ifeq "$(COMPILER)" "" +COMPILER := GCC +endif + +# Set default compiler optimization levels +ifeq "$(MAKECMDGOALS)" "release" +# Default optimization level for "release" builds (make release) +MXC_OPTIMIZE_CFLAGS ?= -O2 +DEBUG = 0 +endif + +ifeq ($(DEBUG),1) +# Optimizes for debugging as recommended +# by GNU for code-edit-debug cycles +# https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options +MXC_OPTIMIZE_CFLAGS := -Og +endif + +# Default level if not building for release or explicitly for debug +MXC_OPTIMIZE_CFLAGS ?= -O2 + +# Set compiler flags +PROJ_CFLAGS += -Wall # Enable warnings +PROJ_CFLAGS += -DMXC_ASSERT_ENABLE + +# Set hardware floating point acceleration. +# Options are: +# - hard +# - soft +# - softfp (default if MFLOAT_ABI is not set) +MFLOAT_ABI ?= softfp +# MFLOAT_ABI must be exported to other Makefiles +export MFLOAT_ABI + +# This path contains system-level intialization files for the target micro. Add to the build. +VPATH += $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source + +# ******************************************************************************* +# Secure Boot Tools (SBT) + +# This section integrates the Secure Boot Tools. It's intended for use with +# microcontrollers that have a secure bootloader. + +# Enabling SBT integration will add some special rules, such as "make sla", "make scpa", etc. + +# Configuration variables: +# SBT : Toggle SBT integration. Set to 1 to enable, or 0 +# to disable +# MAXIM_SBT_DIR : Specify the location of the SBT tool binaries. This defaults to +# Tools/SBT in the MaximSDK. The standalone SBT installer will override +# this via an environment variable. +# TARGET_SEC : Specify the part number to be passed into the SBT. This should match +# the secure variant part #. The default value will depend on TARGET. +# For example, TARGET=MAX32650 will result in TARGET_SEC=MAX32651, and +# the default selection happens in Tools/SBT/SBT-config. +# However, if there are multiple secure part #s for the target +# microcontroller this variable may need to be changed. + +SBT ?= 0 +ifeq ($(SBT), 1) +MAXIM_SBT_DIR ?= $(MAXIM_PATH)/Tools/SBT +MAXIM_SBT_DIR := $(subst \,/,$(MAXIM_SBT_DIR)) +# ^ Must sanitize path for \ on Windows, since this may come from an environment +# variable. + +export MAXIM_SBT_DIR # SBTs must have this environment variable defined to work + +# SBT-config.mk and SBT-rules.mk are included further down this Makefile. + +endif # SBT + +# ******************************************************************************* +# Default goal selection. This section allows you to override the default goal +# that will run if no targets are specified on the command-line. +# (ie. just running 'make' instead of 'make all') + +# Configuration variables: +# .DEFAULT_GOAL : Set the default goal if no targets were specified on the +# command-line +# ** "override" must be used with this variable. ** +# Ex: "override .DEFAULT_GOAL = mygoal" + +ifeq "$(.DEFAULT_GOAL)" "" +ifeq ($(SBT),1) +override .DEFAULT_GOAL := sla +else +override .DEFAULT_GOAL := all +endif +endif + +# Developer note: 'override' is used above for legacy Makefile compatibility. +# gcc.mk/gcc_riscv.mk need to hard-set 'all' internally, so this new system +# uses 'override' to come in over the top without breaking old projects. + +# It's also necessary to explicitly set MAKECMDGOALS... +ifeq "$(MAKECMDGOALS)" "" +MAKECMDGOALS:=$(.DEFAULT_GOAL) +endif + +# Enable colors when --sync-output is used. +# See https://www.gnu.org/software/make/manual/make.html#Terminal-Output (section 13.2) +ifneq ($(MAKE_TERMOUT),) +PROJ_CFLAGS += -fdiagnostics-color=always +endif + +ifneq ($(FORCE_COLOR),) +PROJ_CFLAGS += -fdiagnostics-color=always +endif + +# ******************************************************************************* +# Include SBT config. We need to do this here because it needs to know +# the current MAKECMDGOAL. +ifeq ($(SBT),1) +include $(MAXIM_PATH)/Tools/SBT/SBT-config.mk +endif + +# ******************************************************************************* +# Libraries + +# This section offers "toggle switches" to include or exclude the libraries that +# are available in the MaximSDK. Set a configuration variable to 1 to include the +# library in the build, or 0 to exclude. + +# Each library may also have its own library specific configuration variables. See +# Libraries/libs.mk for more details. + +# Configuration variables: +# - LIB_BOARD : Include the Board-Support Package (BSP) library. (Enabled by default) +# - LIB_PERIPHDRIVERS : Include the peripheral driver library. (Enabled by default) +# - LIB_CMSIS_DSP : Include the CMSIS-DSP library. +# - LIB_CORDIO : Include the Cordio BLE library +# - LIB_FCL : Include the Free Cryptographic Library (FCL) +# - LIB_FREERTOS : Include the FreeRTOS and FreeRTOS-Plus-CLI libraries +# - LIB_LC3 : Include the Low Complexity Communication Codec (LC3) library +# - LIB_LITTLEFS : Include the "little file system" (littleFS) library +# - LIB_LWIP : Include the lwIP library +# - LIB_MAXUSB : Include the MAXUSB library +# - LIB_SDHC : Include the SDHC library + +include $(LIBS_DIR)/libs.mk + + +# ******************************************************************************* +# Rules + +# Include the rules for building for this target. All other makefiles should be +# included before this one. +include $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/$(COMPILER)/$(TARGET_LC).mk + +# Include the rules that integrate the SBTs. SBTs are a special case that must be +# include after the core gcc rules to extend them. +ifeq ($(SBT), 1) +include $(MAXIM_PATH)/Tools/SBT/SBT-rules.mk +endif + + +# Get .DEFAULT_GOAL working. +ifeq "$(MAKECMDGOALS)" "" +MAKECMDGOALS:=$(.DEFAULT_GOAL) +endif + + +all: +# Extend the functionality of the "all" recipe here + arm-none-eabi-size --format=berkeley $(BUILD_DIR)/$(PROJECT).elf + +libclean: + $(MAKE) -f ${PERIPH_DRIVER_DIR}/periphdriver.mk clean.periph + +clean: +# Extend the functionality of the "clean" recipe here + +# The rule to clean out all the build products. +distclean: clean libclean diff --git a/Examples/MAX78002/SPI_ControllerTarget/README.md b/Examples/MAX78002/SPI_ControllerTarget/README.md new file mode 100644 index 00000000000..15e706b1816 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/README.md @@ -0,0 +1,55 @@ +## Description + +This example demonstrates a SPI transaction between two distinct SPI peripherals on the MAX78002. + +SPI1 is setup as the controller (L. Master) in this example and is configured by default to send/receive 1024 8-bit words to and from the slave. Likewise, SPI0 is setup as the slave and is also expecting to both send and receive 1024 8-bit words to and from the master. + +Once the controller ends the transaction, the data received by the controller (L. Master) and the target (L. Slave) is compared to the data sent by their counterpart to ensure all bytes were received properly. + +This example also demonstrates the three available Target Select (TS) control schemes for the Controller which allow users to set up custom TS pins. By default, the example is set to `TSCONTROL_HW_AUTO`. The hardware automatically asserts/deasserts the pre-set TS pins. To use a custom TS pin where the SPI v2 Driver handles the TS assertions, reset the `TSCONTROL_HW_AUTO` macro to 0 and set the `TSCONTROL_SW_DRV` macro to 1. To let the Application handle the TS assertions, set the `TSCONTROL_SW_APP` macro to 1 instead. + + +Target Select (CS) Pin Connections +- TSCONTROL_HW_AUTO: Connect (P0.4 to P0.20). +- TSCONTROL_SW_DRV and TSCONTROL_SW_APP: Connect (P0.4 to P0.12). + +## Software + +This project uses the SPI v2 library. More information on the SPI v2 library can be found in the **[MSDK User Guide Developer Notes](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#spi-v2-library)**. + +### Project Usage + +Universal instructions on building, flashing, and debugging this project can be found in the **[MSDK User Guide](https://analog-devices-msdk.github.io/msdk/USERGUIDE/)**. + +### Project-Specific Build Notes + +Set `MXC_SPI_VERSION=v2` to build the SPI v2 libraries. + +## Required Connections + +- Connect a USB cable between the PC and the CN2 (USB/PWR) connector. +- Connect the 5V power cable at (5V IN). +- Close jumper (RX - P0.0) and (TX - P0.1) at Headers JP23 (UART 0 EN). +- Open an terminal application on the PC and connect to the EV kit's console UART at 115200, 8-N-1. +- Close jumper JP1 (LED1 EN). +- Close jumper JP2 (LED2 EN). +- Connect the SPI pins on headers JH6 and JH9. (P0.4-->P0.20 (CS), P0.5-->P0.21 (MOSI), P0.6-->P0.22 (MISO), and P0.7-->P0.23 (SCK)) +- If custom target select pin was selected, re-connect the CS pins (P0.4-->P0.12). + +## Expected Output + +The Console UART of the device will output these messages: + +``` +************************ SPI Controller-Target Example ************************ +This example sends data between two SPI peripherals in the MAX78002. +SPI1 is configured as the target (L. Slave) and SPI0 is configured +as the controller (L. Master). Each SPI peripheral sends 1024 bytes +on the SPI bus. If the data received by each SPI instance matches the +the data sent by the other instance, then the green LED will illuminate, +otherwise the red LED will illuminate. + +Press PB1 to begin transaction. + +Example Succeeded +``` diff --git a/Examples/MAX78002/SPI_ControllerTarget/SPI_ControllerTarget.launch b/Examples/MAX78002/SPI_ControllerTarget/SPI_ControllerTarget.launch new file mode 100644 index 00000000000..dea825688d0 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/SPI_ControllerTarget.launch @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/MAX78002/SPI_ControllerTarget/main.c b/Examples/MAX78002/SPI_ControllerTarget/main.c new file mode 100644 index 00000000000..e7349aee3fd --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/main.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Maxim Integrated + * Products, Inc. shall not be used except as stated in the Maxim Integrated + * Products, Inc. Branding Policy. + * + * The mere transfer of this software does not imply any licenses + * of trade secrets, proprietary technology, copyrights, patents, + * trademarks, maskwork rights, or any other form of intellectual + * property whatsoever. Maxim Integrated Products, Inc. retains all + * ownership rights. + * + ******************************************************************************/ + +/** + * @file main.c + * @brief SPI_ControllerTarget Demo + * @details Shows Controller and Target transactions between two SPI instances. + */ + +/***** Includes *****/ +#include +#include +#include + +#include "gpio.h" +#include "led.h" +#include "mxc_device.h" +#include "mxc_pins.h" +#include "nvic_table.h" +#include "pb.h" +#include "spi.h" + +/***** Preprocessors *****/ + +#define TARGET_DMA 0 + +// Target Select Control Scheme +#define TSCONTROL_HW_AUTO 1 // Hardware asserts/deasserts TSn pins. +#define TSCONTROL_SW_APP 0 // Application asserts/deasserts custom TS pins. + +// Preprocessor Error Checking +#if (!(TSCONTROL_HW_AUTO || TSCONTROL_SW_APP)) +#error "You must set either TSCONTROL_HW_AUTO or TSCONTROL_SW_APP." +#endif +#if (TSCONTROL_HW_AUTO && TSCONTROL_SW_APP) +#error "You must select either TSCONTROL_HW_AUTO or TSCONTROL_SW_APP." +#endif + +/***** Definitions *****/ + +#define DATA_LEN 1024 // Words +#define DATA_SIZE 8 +#define VALUE 0xFF +#define SPI_SPEED 100000 // Bit Rate (Max.: 1,850,000) + +#define SPI_CONTROLLER MXC_SPI1 +#define SPI_CONTROLLER_TSIDX 0 +#define SPI_TARGET MXC_SPI0 +#define SPI_TARGET_TSIDX 0 +#define SPI_TARGET_IRQ SPI0_IRQn + +/***** Globals *****/ +uint8_t controller_rx[DATA_LEN]; +uint8_t controller_tx[DATA_LEN]; +uint8_t target_rx[DATA_LEN]; +uint8_t target_tx[DATA_LEN]; +uint8_t TX_DMA_CH, RX_DMA_CH; + +/***** Functions *****/ +void SPI_Target_IRQHandler(void) +{ + MXC_SPI_AsyncHandler(SPI_TARGET); +} + +#if TARGET_DMA +void DMA_TX_IRQHandler(void) +{ + MXC_SPI_DMA_TX_Handler(SPI_TARGET); +} + +void DMA_RX_IRQHandler(void) +{ + MXC_SPI_DMA_RX_Handler(SPI_TARGET); +} +#endif + +int main(void) +{ + int error; + uint8_t ts_active_pol_mask = 0; + + // Controller (L. Master) + mxc_spi_pins_t controller_pins; + mxc_spi_cfg_t controller_cfg; + mxc_spi_req_t controller_req; + + // Target (L. Slave) + mxc_spi_pins_t target_pins; + mxc_spi_cfg_t target_cfg; + mxc_spi_req_t target_req; + + printf("\n************************ SPI Controller-Target Example ************************\n"); + printf("This example sends data between two SPI peripherals in the MAX78002.\n"); + printf("SPI%d is configured as the ts (L. Slave) and SPI%d is configured\n", + MXC_SPI_GET_IDX(SPI_TARGET), MXC_SPI_GET_IDX(SPI_CONTROLLER)); + printf("as the controller (L. Master). Each SPI peripheral sends %d bytes\n", DATA_LEN); + printf("on the SPI bus. If the data received by each SPI instance matches the\n"); + printf("the data sent by the other instance, then the green LED will illuminate,\n"); + printf("otherwise the red LED will illuminate.\n\n"); + +#if TSCONTROL_SW_APP + printf("A custom Target Select pin was set up for the Controller (SPI%d).\n", + MXC_SPI_GET_IDX(SPI_CONTROLLER)); + printf("Please connect the custom TS pins: P0.4 to P0.12.\n\n"); +#else // TSCONTROL_HW_AUTO + printf("Please connect the HW TS pins: P0.4 to P0.20.\n\n"); +#endif + + /***** Initialize data buffers *****/ + for (int i = 0; i < DATA_LEN; i++) { + controller_tx[i] = i; + target_tx[i] = i; + } + + memset(controller_rx, 0x0, DATA_LEN * sizeof(uint8_t)); + memset(target_rx, 0x0, DATA_LEN * sizeof(uint8_t)); + + /***** Configure Controller (L. Master) *****/ + + controller_cfg.spi = SPI_CONTROLLER; + controller_cfg.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 + controller_cfg.frame_size = DATA_SIZE; + controller_cfg.use_dma_tx = false; + controller_cfg.use_dma_rx = false; + + // Target Select Settings +#if TSCONTROL_HW_AUTO + // Initialize HW TS0 pin. + controller_pins.ss0 = true; + controller_pins.ss1 = false; + controller_pins.ss2 = false; + controller_pins.vddioh = false; + controller_pins.drvstr = MXC_GPIO_DRVSTR_0; + + // This demonstrates how to set the Active Polarity for each TSn pin. + // This setting is passed into MXC_SPI_Init(...) and should match between + // the Controller and Target. + // ts_active_pol_mask[0] = 1 -> Active HIGH (1) + // ts_active_pol_mask[1] = 0 -> Active LOW (0) + // ts_active_pol_mask[2] = 0 -> Active LOW (0) + ts_active_pol_mask = 0b0001; + +#else // TSCONTROL_SW_DRV or TSCONTROL_SW_APP + // Example to set up a custom TS pin with Active HIGH polarity. + mxc_gpio_cfg_t ts_pins; + ts_pins.port = MXC_GPIO0; + ts_pins.mask = MXC_GPIO_PIN_12; + ts_pins.func = MXC_GPIO_FUNC_OUT; + ts_pins.pad = MXC_GPIO_PAD_NONE; + ts_pins.vssel = MXC_GPIO_VSSEL_VDDIO; // Set custom ts pin to VDDIO. + + // Don't initialize HW TS pins in this scheme. + controller_pins.ss0 = false; + controller_pins.ss1 = false; + controller_pins.ss2 = false; + controller_pins.vddioh = false; + controller_pins.drvstr = MXC_GPIO_DRVSTR_0; + + // No HW TS pins are used in this scheme. + ts_active_pol_mask = 0; + + // Configure the custom TS pin. + MXC_GPIO_Config(&ts_pins); + // Active HIGH, Idle LOW. + MXC_GPIO_OutClr(ts_pins.port, ts_pins.mask); +#endif + + error = MXC_SPI_Init(SPI_CONTROLLER, MXC_SPI_TYPE_CONTROLLER, MXC_SPI_INTERFACE_STANDARD, 0, + ts_active_pol_mask, SPI_SPEED, controller_pins); + if (error != E_NO_ERROR) { + printf("\nSPI CONTROLLER INITIALIZATION ERROR\n"); + while (1) {} + } + + error = MXC_SPI_Config(&controller_cfg); + if (error != E_NO_ERROR) { + printf("\nSPI CONTROLLER CONFIGURATION ERROR\n"); + while (1) {} + } + + // Setup Controller Request. + controller_req.spi = SPI_CONTROLLER; + controller_req.txData = (uint8_t *)controller_tx; + controller_req.txLen = DATA_LEN; + controller_req.rxData = (uint8_t *)controller_rx; + controller_req.rxLen = DATA_LEN; + controller_req.ssDeassert = 1; + controller_req.completeCB = NULL; + + /***** Configure Target (L. Slave) *****/ + // Initialize HW TS0 pin. + target_pins.ss0 = true; + target_pins.ss1 = false; + target_pins.ss2 = false; + target_pins.vddioh = false; + target_pins.drvstr = MXC_GPIO_DRVSTR_0; + + // This demonstrates how to set the Active Polarity for each TSn pin. + // This setting is passed into MXC_SPI_Init(...) and should match between + // the Controller and Target. + // ts_active_pol_mask[0] = 1 -> Active HIGH (1) + // ts_active_pol_mask[1] = 0 -> Active LOW (0) + // ts_active_pol_mask[2] = 0 -> Active LOW (0) + ts_active_pol_mask = 0b0001; + + target_cfg.spi = SPI_TARGET; + target_cfg.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 + target_cfg.frame_size = DATA_SIZE; + +#if TARGET_DMA + target_cfg.use_dma_tx = true; + target_cfg.use_dma_rx = true; + target_cfg.dma = MXC_DMA; +#else + target_cfg.use_dma_tx = false; + target_cfg.use_dma_rx = false; +#endif + + error = MXC_SPI_Init(SPI_TARGET, MXC_SPI_TYPE_TARGET, MXC_SPI_INTERFACE_STANDARD, 0, + ts_active_pol_mask, SPI_SPEED, target_pins); + if (error != E_NO_ERROR) { + printf("\nSPI TARGET INITIALIZATION ERROR\n"); + while (1) {} + } + + error = MXC_SPI_Config(&target_cfg); + if (error != E_NO_ERROR) { + printf("\nSPI TARGET CONFIGURATION ERROR\n"); + while (1) {} + } + + // Setup Target Request. + target_req.spi = SPI_TARGET; + target_req.txData = (uint8_t *)target_tx; + target_req.txLen = DATA_LEN; + target_req.rxData = (uint8_t *)target_rx; + target_req.rxLen = DATA_LEN; + target_req.ssDeassert = 1; + target_req.completeCB = NULL; + +#if TARGET_DMA + TX_DMA_CH = MXC_SPI_DMA_GetTXChannel(SPI_TARGET); + RX_DMA_CH = MXC_SPI_DMA_GetRXChannel(SPI_TARGET); + + NVIC_EnableIRQ(MXC_DMA_CH_GET_IRQ(TX_DMA_CH)); + NVIC_EnableIRQ(MXC_DMA_CH_GET_IRQ(RX_DMA_CH)); + + MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(TX_DMA_CH), DMA_TX_IRQHandler); + MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(RX_DMA_CH), DMA_RX_IRQHandler); +#else + MXC_NVIC_SetVector(SPI_TARGET_IRQ, SPI_Target_IRQHandler); + NVIC_EnableIRQ(SPI_TARGET_IRQ); +#endif + + printf("Press PB1 to begin transaction.\n"); + while (!PB_Get(0)) {} + + /***** Perform Transaction *****/ +#if TARGET_DMA + MXC_SPI_TargetTransactionDMA(&target_req); +#else + MXC_SPI_TargetTransactionAsync(&target_req); +#endif + +#if TSCONTROL_SW_APP + // Assert custom TS pin. + MXC_GPIO_OutToggle(ts_pins.port, ts_pins.mask); +#endif + + MXC_SPI_ControllerTransaction(&controller_req); + +#if TSCONTROL_SW_APP + MXC_GPIO_OutToggle(ts_pins.port, ts_pins.mask); +#endif + + /***** Verify Results *****/ + if (memcmp(target_rx, controller_tx, sizeof(controller_tx)) != 0) { // Controller->Target + printf("\nTarget failed to receive data.\n"); + LED_On(1); + return E_COMM_ERR; + } else if (memcmp(controller_rx, target_tx, sizeof(target_tx)) != 0) { // Target->Controller + printf("\nController failed to receive data.\n"); + LED_On(1); + return E_COMM_ERR; + } + + MXC_SPI_Shutdown(SPI_CONTROLLER); + MXC_SPI_Shutdown(SPI_TARGET); + + LED_On(0); // Indicates SUCCESS + printf("\nExample Succeeded\n"); + return E_NO_ERROR; +} diff --git a/Examples/MAX78002/SPI_ControllerTarget/project.mk b/Examples/MAX78002/SPI_ControllerTarget/project.mk new file mode 100644 index 00000000000..675155fcc10 --- /dev/null +++ b/Examples/MAX78002/SPI_ControllerTarget/project.mk @@ -0,0 +1,17 @@ +# This file can be used to set build configuration +# variables. These variables are defined in a file called +# "Makefile" that is located next to this one. + +# For instructions on how to use this system, see +# https://analog-devices-msdk.github.io/msdk/USERGUIDE/#build-system + +#MXC_OPTIMIZE_CFLAGS = -Og +# ^ For example, you can uncomment this line to +# optimize the project for debugging + +# ********************************************************** + +# Add your config here! + +# Build SPI v2 library for example. +MXC_SPI_VERSION = v2 diff --git a/Examples/MAX78002/SPI_MasterSlave/.vscode/README.md b/Examples/MAX78002/SPI_MasterSlave/.vscode/README.md old mode 100755 new mode 100644 diff --git a/Examples/MAX78002/SPI_MasterSlave/.vscode/launch.json b/Examples/MAX78002/SPI_MasterSlave/.vscode/launch.json old mode 100755 new mode 100644 diff --git a/Examples/MAX78002/SPI_MasterSlave/.vscode/settings.json b/Examples/MAX78002/SPI_MasterSlave/.vscode/settings.json old mode 100755 new mode 100644 diff --git a/Examples/MAX78002/SPI_MasterSlave/.vscode/tasks.json b/Examples/MAX78002/SPI_MasterSlave/.vscode/tasks.json old mode 100755 new mode 100644 diff --git a/Examples/MAX78002/SPI_MasterSlave/README.md b/Examples/MAX78002/SPI_MasterSlave/README.md index 25a7737c518..70c132cebb2 100644 --- a/Examples/MAX78002/SPI_MasterSlave/README.md +++ b/Examples/MAX78002/SPI_MasterSlave/README.md @@ -8,9 +8,7 @@ Once the master ends the transaction, the data received by the master and the sl ## Software -### SPI v2 Library - -The SPI v2 Library does not support Target (L. Slave) Transaction functions yet. To use the previous SPI driver, set `MXC_SPI_BUILD_LEGACY=1` in the Project's project.mk file. +This project uses the SPI v2 library. More information on the SPI v2 library can be found in the **[MSDK User Guide Developer Notes](https://analog-devices-msdk.github.io/msdk/USERGUIDE/#spi-v2-library)**. ### Project Usage @@ -18,7 +16,7 @@ Universal instructions on building, flashing, and debugging this project can be ### Project-Specific Build Notes -(None - this project builds as a standard example) +Set `MXC_SPI_VERSION=v2` to build the SPI v2 libraries. ## Required Connections diff --git a/Examples/MAX78002/SPI_MasterSlave/main.c b/Examples/MAX78002/SPI_MasterSlave/main.c index be9d5757e36..cd191ab307f 100644 --- a/Examples/MAX78002/SPI_MasterSlave/main.c +++ b/Examples/MAX78002/SPI_MasterSlave/main.c @@ -157,6 +157,7 @@ int main(void) /***** Perform Transaction *****/ MXC_SPI_SlaveTransactionAsync(&slave_req); + MXC_SPI_MasterTransaction(&master_req); /***** Verify Results *****/ diff --git a/Examples/MAX78002/SPI_MasterSlave/project.mk b/Examples/MAX78002/SPI_MasterSlave/project.mk index b4897bd5857..9caf04b905b 100644 --- a/Examples/MAX78002/SPI_MasterSlave/project.mk +++ b/Examples/MAX78002/SPI_MasterSlave/project.mk @@ -9,6 +9,5 @@ # Add your config here! -# SPI v2 does not support Target (L. Slave) Transaction functions yet. -# Set the MXC_SPI_BUILD_LEGACY to 1 to build the previous SPI library. -MXC_SPI_BUILD_LEGACY=1 +# Build SPI v2 library for example. +MXC_SPI_VERSION = v2 diff --git a/Libraries/Boards/MAX78002/EvKit_V1/Source/board.c b/Libraries/Boards/MAX78002/EvKit_V1/Source/board.c index b077ba931c1..64c48be65fc 100644 --- a/Libraries/Boards/MAX78002/EvKit_V1/Source/board.c +++ b/Libraries/Boards/MAX78002/EvKit_V1/Source/board.c @@ -118,9 +118,19 @@ void mxc_assert(const char *expr, const char *file, int line) /******************************************************************************/ /** - * NOTE: This weak definition is included to support Push Button interrupts in + * NOTE: This weak definition is included to support Touchscreen and Push Button interrupts in * case the user does not define this interrupt handler in their application. **/ +__weak void GPIO0_IRQHandler(void) +{ + MXC_GPIO_Handler(MXC_GPIO_GET_IDX(MXC_GPIO0)); +} + +__weak void GPIO1_IRQHandler(void) +{ + MXC_GPIO_Handler(MXC_GPIO_GET_IDX(MXC_GPIO1)); +} + __weak void GPIO2_IRQHandler(void) { MXC_GPIO_Handler(MXC_GPIO_GET_IDX(MXC_GPIO2)); diff --git a/Libraries/Boards/MAX78002/EvKit_V1/board.mk b/Libraries/Boards/MAX78002/EvKit_V1/board.mk index bc38cdf0f6a..416bb2bc581 100644 --- a/Libraries/Boards/MAX78002/EvKit_V1/board.mk +++ b/Libraries/Boards/MAX78002/EvKit_V1/board.mk @@ -105,11 +105,6 @@ PROJ_CFLAGS+=-DCAMERA_OV7692 endif SRCS += sccb.c -ifeq "$(MXC_SPI_BUILD_LEGACY)" "1" -MXC_SPI_LEGACY=1 -PROJ_CFLAGS+=-DMXC_SPI_LEGACY -endif - MISC_DRIVERS_DIR ?= $(MAXIM_PATH)/Libraries/MiscDrivers # Where to find BSP source files diff --git a/Libraries/Boards/MAX78002/EvKit_V1/examples.txt b/Libraries/Boards/MAX78002/EvKit_V1/examples.txt index ceb736019a1..b70e3f39870 100644 --- a/Libraries/Boards/MAX78002/EvKit_V1/examples.txt +++ b/Libraries/Boards/MAX78002/EvKit_V1/examples.txt @@ -57,6 +57,7 @@ RTC_Backup SDHC_FAT SDHC_Raw SPI +SPI_ControllerTarget SPI_MasterSlave Temp_Monitor TFT_Demo diff --git a/Libraries/CMSIS/Device/Maxim/GCC/gcc.mk b/Libraries/CMSIS/Device/Maxim/GCC/gcc.mk index 2d95a2ad0b4..79aa98ec5e1 100644 --- a/Libraries/CMSIS/Device/Maxim/GCC/gcc.mk +++ b/Libraries/CMSIS/Device/Maxim/GCC/gcc.mk @@ -618,6 +618,6 @@ $(BUILD_DIR)/_empty_tmp_file.c: | $(BUILD_DIR) .PHONY: project_defines project_defines: $(BUILD_DIR)/project_defines.h -$(BUILD_DIR)/project_defines.h: $(BUILD_DIR)/_empty_tmp_file.c | $(BUILD_DIR) +$(BUILD_DIR)/project_defines.h: $(BUILD_DIR)/_empty_tmp_file.c $(PROJECTMK) | $(BUILD_DIR) @echo "// This is a generated file that's used to detect definitions that have been set by the compiler and build system." > $@ @$(CC) -E -P -dD $(BUILD_DIR)/_empty_tmp_file.c $(filter-out -MD,$(CFLAGS)) >> $@ diff --git a/Libraries/CMSIS/Device/Maxim/GCC/gcc_riscv.mk b/Libraries/CMSIS/Device/Maxim/GCC/gcc_riscv.mk index c66d9519603..1b9af120f0e 100644 --- a/Libraries/CMSIS/Device/Maxim/GCC/gcc_riscv.mk +++ b/Libraries/CMSIS/Device/Maxim/GCC/gcc_riscv.mk @@ -615,6 +615,6 @@ $(BUILD_DIR)/_empty_tmp_file.c: | $(BUILD_DIR) .PHONY: project_defines project_defines: $(BUILD_DIR)/project_defines.h -$(BUILD_DIR)/project_defines.h: $(BUILD_DIR)/_empty_tmp_file.c | $(BUILD_DIR) +$(BUILD_DIR)/project_defines.h: $(BUILD_DIR)/_empty_tmp_file.c $(PROJECTMK) | $(BUILD_DIR) @echo "// This is a generated file that's used to detect definitions that have been set by the compiler and build system." > $@ @$(CC) -E -P -dD $(BUILD_DIR)/_empty_tmp_file.c $(filter-out -MD,$(CFLAGS)) >> $@ diff --git a/Libraries/PeriphDrivers/Include/MAX78002/gpio.h b/Libraries/PeriphDrivers/Include/MAX78002/gpio.h index 647d94f6571..dcee404ac87 100644 --- a/Libraries/PeriphDrivers/Include/MAX78002/gpio.h +++ b/Libraries/PeriphDrivers/Include/MAX78002/gpio.h @@ -221,29 +221,29 @@ int MXC_GPIO_Config(const mxc_gpio_cfg_t *cfg); /** * @brief Gets the pin(s) input state. - * @param cfg Pointer to configuration structure describing the pin. - * @param mask Mask of the pin to read + * @param port Pointer to the selected GPIO port instance. + * @param mask Mask of the pin to read. * @return The requested pin state. */ uint32_t MXC_GPIO_InGet(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Sets the pin(s) to a high level output. - * @param cfg Pointer to configuration structure describing the pin. - * @param mask Mask of the pin to set + * @param port Pointer to the selected GPIO port instance. + * @param mask Mask of the pin to set. */ void MXC_GPIO_OutSet(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Clears the pin(s) to a low level output. - * @param cfg Pointer to configuration structure describing the pin. - * @param mask Mask of the pin to clear + * @param port Pointer to the selected GPIO port instance. + * @param mask Mask of the pin to clear. */ void MXC_GPIO_OutClr(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Gets the pin(s) output state. - * @param cfg Pointer to configuration structure describing the pin. + * @param port Pointer to the selected GPIO port instance. * @param mask Mask of the pin to read the output state of * @return The state of the requested pin. * @@ -252,8 +252,8 @@ uint32_t MXC_GPIO_OutGet(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Write the pin(s) to a desired output level. - * @param cfg Pointer to configuration structure describing the pin. - * @param mask Mask of the pin to set output level of + * @param port Pointer to the selected GPIO port instance. + * @param mask Mask of the pin to set output level. * @param val Desired output level of the pin(s). This will be masked * with the configuration mask. */ @@ -261,7 +261,7 @@ void MXC_GPIO_OutPut(mxc_gpio_regs_t *port, uint32_t mask, uint32_t val); /** * @brief Toggles the the pin(s) output level. - * @param cfg Pointer to configuration structure describing the pin. + * @param port Pointer to the selected GPIO port instance. * @param mask Mask of the pin to toggle the output */ void MXC_GPIO_OutToggle(mxc_gpio_regs_t *port, uint32_t mask); @@ -276,23 +276,23 @@ int MXC_GPIO_IntConfig(const mxc_gpio_cfg_t *cfg, mxc_gpio_int_pol_t pol); /** * @brief Enables the specified GPIO interrupt - * @param cfg Pointer to configuration structure describing the pin. - * @param mask mask of the pin to enable interrupt + * @param port Pointer to the selected GPIO port instance. + * @param mask Mask of the pin to enable interrupt. * */ void MXC_GPIO_EnableInt(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Disables the specified GPIO interrupt. - * @param cfg Pointer to configuration structure describing the pin. - * @param mask mask of the pin to disable interrupt + * @param port Pointer to the selected GPIO port instance. + * @param mask Mask of the pin to disable interrupt. */ void MXC_GPIO_DisableInt(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Gets the interrupt(s) status on a GPIO port * - * @param port Pointer to the port requested + * @param port Pointer to the selected GPIO port instance. * * @return The requested interrupt status. */ @@ -301,7 +301,7 @@ uint32_t MXC_GPIO_GetFlags(mxc_gpio_regs_t *port); /** * @brief Gets the interrupt(s) status on a GPIO port * - * @param port Pointer to the port requested + * @param port Pointer to the selected GPIO port instance. * @param flags The flags to clear */ void MXC_GPIO_ClearFlags(mxc_gpio_regs_t *port, uint32_t flags); @@ -328,7 +328,7 @@ void MXC_GPIO_Handler(unsigned int port); /** * @brief Set Voltage select for pins to VDDIO or VDDIOH * - * @param port The GPIO port + * @param port Pointer to the selected GPIO port instance. * @param[in] vssel VDDIO or VDDIOH to set the voltatge to * @param[in] mask Pins in the GPIO port that will be set to the voltage. */ @@ -337,7 +337,7 @@ int MXC_GPIO_SetVSSEL(mxc_gpio_regs_t *port, mxc_gpio_vssel_t vssel, uint32_t ma /** * @brief Enables GPIO pins to be used as a wakeup source. * - * @param port The GPIO port + * @param port Pointer to the selected GPIO port instance. * @param mask Pins in the GPIO port that will be enabled as a wakeup source. */ void MXC_GPIO_SetWakeEn(mxc_gpio_regs_t *port, uint32_t mask); @@ -345,7 +345,7 @@ void MXC_GPIO_SetWakeEn(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Disables GPIO pins from being used as a wakeup source. * - * @param port The GPIO port + * @param port Pointer to the selected GPIO port instance. * @param mask Pins in the GPIO port that will be disabled as a wakeup source. */ void MXC_GPIO_ClearWakeEn(mxc_gpio_regs_t *port, uint32_t mask); @@ -353,7 +353,7 @@ void MXC_GPIO_ClearWakeEn(mxc_gpio_regs_t *port, uint32_t mask); /** * @brief Returns the pins currently enabled as wakeup sources. * - * @param port The GPIO port to check. + * @param port Pointer to the selected GPIO port instance. * * @returns The value of the wake enable register. */ @@ -362,7 +362,7 @@ uint32_t MXC_GPIO_GetWakeEn(mxc_gpio_regs_t *port); /** * @brief Set Drive Strength for pins. * - * @param port The GPIO port. + * @param port Pointer to the selected GPIO port instance. * @param[in] ds Drive strength level. Ref /mxc_gpio_ds_t enum type. * @param[in] mask Pins in the GPIO port that will be set to the voltage. */ diff --git a/Libraries/PeriphDrivers/Include/MAX78002/spi.h b/Libraries/PeriphDrivers/Include/MAX78002/spi.h index b02e92e1aeb..404e8c25a5f 100644 --- a/Libraries/PeriphDrivers/Include/MAX78002/spi.h +++ b/Libraries/PeriphDrivers/Include/MAX78002/spi.h @@ -68,10 +68,10 @@ extern "C" { * @brief The list of types for the SPI peripheral. */ typedef enum { - MXC_SPI_TYPE_MASTER = 0, - MXC_SPI_TYPE_CONTROLLER = 0, - MXC_SPI_TYPE_SLAVE = 1, - MXC_SPI_TYPE_TARGET = 1 + MXC_SPI_TYPE_SLAVE = 0, + MXC_SPI_TYPE_TARGET = 0, + MXC_SPI_TYPE_MASTER = 1, + MXC_SPI_TYPE_CONTROLLER = 1 } mxc_spi_type_t; /** @@ -80,8 +80,7 @@ typedef enum { */ typedef enum { MXC_SPI_TSCONTROL_HW_AUTO = 0, // Automatically by hardware - MXC_SPI_TSCONTROL_SW_DRV = 1, // Through software by the driver - MXC_SPI_TSCONTROL_SW_APP = 2 // Through software in the application + MXC_SPI_TSCONTROL_SW_APP = 1 // Through software in the application } mxc_spi_tscontrol_t; /** @@ -96,11 +95,11 @@ typedef enum { * @brief The list of supported SPI Interface Modes. */ typedef enum { - MXC_SPI_INTERFACE_3WIRE = 0, - MXC_SPI_INTERFACE_STANDARD = 1, - MXC_SPI_INTERFACE_4WIRE = 1, - MXC_SPI_INTERFACE_DUAL = 2, - MXC_SPI_INTERFACE_QUAD = 3 + MXC_SPI_INTERFACE_STANDARD = 0, + MXC_SPI_INTERFACE_4WIRE = 0, + MXC_SPI_INTERFACE_QUAD = 1, + MXC_SPI_INTERFACE_3WIRE = 2, + MXC_SPI_INTERFACE_DUAL = 3 } mxc_spi_interface_t; /** @@ -120,25 +119,6 @@ typedef enum { MXC_SPI_CLKMODE_3 = 3 // CPOL: 1 CPHA: 1 } mxc_spi_clkmode_t; -/** - * @brief The settings for selecting TARGETS when in the SPI - * peripheral is set in CONTROLLER mode. - * - */ -typedef struct { - uint32_t index; // Select target index for transactions. - mxc_gpio_cfg_t pins; // User-configured Target Select SPI pins. - - // Initialization Settings. - uint8_t active_polarity; // Active High (1) or Low (0). - uint8_t init_mask; // Initialize HW TS pins if TS_CONTROL scheme is in - // MXC_SPI_TSCONTROL_HW_AUTO mode. - // The [] represents the bit location: - // init_mask[0] = Target Select Pin 0 - // init_mask[1] = Target Select Pin 1 - // init_mask[n] = Target Select Pin n -} mxc_spi_target_t; - ///>>> @deprecated /** * @brief The list of SPI Widths supported @@ -171,7 +151,7 @@ typedef enum { } mxc_spi_mode_t; ///<<< Deprecated -typedef struct _mxc_spi_reva2_req_t mxc_spi_req_t; +typedef struct _mxc_spi_req_t mxc_spi_req_t; /** * @brief The callback routine used to indicate the transaction has terminated. @@ -180,96 +160,50 @@ typedef struct _mxc_spi_reva2_req_t mxc_spi_req_t; * @param result See \ref MXC_Error_Codes for the list of error codes. */ typedef void (*mxc_spi_callback_t)(void *, int result); -typedef void (*spi_complete_cb_t)(void *req, int result); +typedef mxc_spi_callback_t spi_complete_cb_t; // Support SPI v1 name. typedef struct _mxc_spi_pins_t mxc_spi_pins_t; struct _mxc_spi_pins_t { - bool clock; ///>> Previous Implementation +//////>>> Previous Implementation /** * @brief Sets the number of bits per character * - * @param spi Pointer to SPI registers (selects the SPI block used.) + * @param spi Pointer to SPI registers (selects the SPI block used). * @param dataSize The number of bits per character * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. @@ -704,7 +619,7 @@ int MXC_SPI_SetDataSize(mxc_spi_regs_t *spi, int dataSize); /** * @brief Gets the number of bits per character * - * @param spi Pointer to SPI registers (selects the SPI block used.) + * @param spi Pointer to SPI registers (selects the SPI block used). * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. */ @@ -713,7 +628,7 @@ int MXC_SPI_GetDataSize(mxc_spi_regs_t *spi); /** * @brief Sets the SPI width used for transmissions * - * @param spi Pointer to SPI registers (selects the SPI block used.) + * @param spi Pointer to SPI registers (selects the SPI block used). * @param spiWidth SPI Width (3-Wire, Standard, Dual SPI, Quad SPI) * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. @@ -723,7 +638,7 @@ int MXC_SPI_SetWidth(mxc_spi_regs_t *spi, mxc_spi_width_t spiWidth); /** * @brief Gets the SPI width used for transmissions * - * @param spi Pointer to SPI registers (selects the SPI block used.) + * @param spi Pointer to SPI registers (selects the SPI block used). * * @return Spi Width */ @@ -755,8 +670,8 @@ int MXC_SPI_GetSlave(mxc_spi_regs_t *spi); /** * @brief Sets the spi mode using clock polarity and clock phase * - * @param spi Pointer to SPI registers (selects the SPI block used.) - * @param spiMode \ref mxc_spi_mode_t + * @param spi Pointer to SPI registers (selects the SPI block used). + * @param spiMode \ref mxc_spi_mode_t * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. */ @@ -765,7 +680,7 @@ int MXC_SPI_SetMode(mxc_spi_regs_t *spi, mxc_spi_mode_t spiMode); /** * @brief Gets the spi mode * - * @param spi Pointer to SPI registers (selects the SPI block used.) + * @param spi Pointer to SPI registers (selects the SPI block used). * * @return mxc_spi_mode_t \ref mxc_spi_mode_t */ @@ -799,32 +714,34 @@ unsigned int MXC_SPI_ReadRXFIFO(mxc_spi_regs_t *spi, unsigned char *bytes, unsig * In single wire master mode, this data is transmitted on MOSI when performing * an RX (MISO) only transaction. This defaults to 0. * - * @param spi Pointer to SPI registers (selects the SPI block used.) + * @param spi Pointer to SPI registers (selects the SPI block used). * @param defaultTXData Data to shift out in RX-only transactions * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. */ int MXC_SPI_SetDefaultTXData(mxc_spi_regs_t *spi, unsigned int defaultTXData); -///<<< Previous Implementation +//////<<< Previous Implementation /* ** DMA Functions ** */ /** * @brief This function initializes the DMA for SPI DMA transactions. * - * @note This function must run before the MXC_SPI_MasterTransactionDMA - * function i + * @note This function must run before any SPI DMA transactions. * - * @param init Pointer to init struct with init.use_dma is set to true - * and a DMA instance is assigned to init.dma (init.dma = MXC_DMA). + * @param spi Pointer to SPI registers (selects the SPI block used). + * @param dma Pointer to DMA registers (selects the DMA block used). + * @param use_dma_tx True/False setting to initialize SPI DMA TX. Acquire DMA TX channel. + * @param use_dma_rx True/False setting to initialize SPI DMA RX. Acquire DMA RX channel. + * use_dma_tx must be true even if use_dma_rx is false. * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. */ -int MXC_SPI_DMA_Init(mxc_spi_init_t *init); +int MXC_SPI_DMA_Init(mxc_spi_regs_t *spi, mxc_dma_regs_t *dma, bool use_dma_tx, bool use_dma_rx); /** * @brief Helper function that checks whether the MXC_SPI_Init function - * initalized DMA for SPI DMA transactons. + * cfgalized DMA for SPI DMA transactons. * * @param spi Pointer to SPI instance's registers. * @@ -856,12 +773,12 @@ int MXC_SPI_DMA_GetRXChannel(mxc_spi_regs_t *spi); * @brief Sets the SPI instance's DMA TX/RX request select. * * @param spi Pointer to SPI instance's registers. - * @param tx_buffer Pointer to transmit buffer. - * @param rx_buffer Pointer to receive buffer. + * @param use_dma_tx True/False setting to set SPI DMA TX request select. + * @param use_dma_rx True/False setting to set SPI DMA RX request select. * * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. */ -int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint8_t *rx_buffer); +int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, bool use_dma_tx, bool use_dma_rx); /* ** Transaction Functions ** */ @@ -920,90 +837,60 @@ int MXC_SPI_MasterTransactionAsync(mxc_spi_req_t *req); int MXC_SPI_MasterTransactionDMA(mxc_spi_req_t *req); /** - * @brief Set up a non-blocking, interrupt-driven SPI controller transaction. - * - * The MXC_SPI_Handler function must be called in the selected SPI instance's - * interrupt handler to process the transaction. + * @brief Set up a blocking, non-interrupt-driven SPI controller transaction. * - * @param spi Pointer to SPI instance's registers. - * @param tx_buffer Pointer to transmit buffer (in terms of bytes). - * @param tx_fr_len Number of frames to transmit from transmit buffer. - * @param rx_buffer Pointer to transmit buffer (in terms of bytes). - * @param rx_fr_len Number of frames to store in recieve buffer. - * @param deassert True(1)/False(0) whether to deassert target select at end of transactions. - * @param target Pointer to select target for SPI transaction. + * The MXC_SPI_Init_v2(..). function must be called before using this transaction + * function. + * + * @param req Pointer to details of the transaction. * * @return See \ref MXC_Error_Codes for the list of error return codes. */ -int MXC_SPI_ControllerTransaction(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target); +int MXC_SPI_ControllerTransaction(mxc_spi_req_t *req); /** - * @brief Set up a blocking, interrupt-driven SPI controller transaction. + * @brief Set up a non-blocking, interrupt-driven SPI controller transaction. * * The MXC_SPI_Handler function must be called in the selected SPI instance's * interrupt handler to process the transaction. + * + * The MXC_SPI_Init_v2(..). function must be called before using this transaction + * function. * - * @param spi Pointer to SPI instance's registers. - * @param tx_buffer Pointer to transmit buffer (in terms of bytes). - * @param tx_fr_len Number of frames to transmit from transmit buffer. - * @param rx_buffer Pointer to transmit buffer (in terms of bytes). - * @param rx_fr_len Number of frames to store in recieve buffer. - * @param deassert True(1)/False(0) whether to deassert target select at end of transactions. - * @param target Pointer to select target for SPI transaction. + * @param req Pointer to details of the transaction. * * @return See \ref MXC_Error_Codes for the list of error return codes. */ -int MXC_SPI_ControllerTransactionB(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target); +int MXC_SPI_ControllerTransactionAsync(mxc_spi_req_t *req); /** * @brief Set up a non-blocking, DMA-driven SPI controller transaction. + * + * The MXC_SPI_Init_v2(..). or MXC_SPI_DMA_Init(..). functions must be + * called before calling this DMA transaction function. This function + * does not initialize the DMA. * - * @param spi Pointer to SPI instance's registers. - * @param tx_buffer Pointer to transmit buffer (in terms of bytes). - * @param tx_fr_len Number of frames to transmit from transmit buffer. - * @param rx_buffer Pointer to transmit buffer (in terms of bytes). - * @param rx_fr_len Number of frames to store in recieve buffer. - * @param deassert True(1)/False(0) whether to deassert target select at end of transactions. - * @param target Pointer to select target for SPI transaction. + * @param req Pointer to details of the transaction. * * @return See \ref MXC_Error_Codes for the list of error return codes. */ -int MXC_SPI_ControllerTransactionDMA(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target); +int MXC_SPI_ControllerTransactionDMA(mxc_spi_req_t *req); /** * @brief Set up a blocking, DMA-driven SPI controller transaction. + * + * The MXC_SPI_Init_v2(..). function must be called before using this transaction + * function. * - * @param spi Pointer to SPI instance's registers. - * @param tx_buffer Pointer to transmit buffer (in terms of bytes). - * @param tx_fr_len Number of frames to transmit from transmit buffer. - * @param rx_buffer Pointer to transmit buffer (in terms of bytes). - * @param rx_fr_len Number of frames to store in recieve buffer. - * @param deassert True(1)/False(0) whether to deassert target select at end of transactions. - * @param target Pointer to select target for SPI transaction. + * @param req Pointer to details of the transaction. * * @return See \ref MXC_Error_Codes for the list of error return codes. */ -int MXC_SPI_ControllerTransactionDMAB(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target); +int MXC_SPI_ControllerTransactionDMAB(mxc_spi_req_t *req); /** * @brief Performs a blocking SPI transaction. * - * Performs a blocking SPI transaction. - * These actions will be performed in Slave Mode: - * 1. Fill FIFO with txData - * 2. Wait for SS Assert - * 3. If needed, pad txData with DefaultTXData - * 4. Unload RX FIFO as needed - * 5. On SS Deassert, return - * * @param req Pointer to details of the transaction * * @return See \ref MXC_Error_Codes for the list of error return codes. @@ -1013,9 +900,6 @@ int MXC_SPI_SlaveTransaction(mxc_spi_req_t *req); /** * @brief Setup an interrupt-driven SPI transaction * - * The TX FIFO will be filled with txData, padded with DefaultTXData if necessary - * Relevant interrupts will be enabled, and relevant registers set (SS, Width, etc) - * * @param req Pointer to details of the transactionz * * @return See \ref MXC_Error_Codes for the list of error return codes. @@ -1039,6 +923,43 @@ int MXC_SPI_SlaveTransactionAsync(mxc_spi_req_t *req); */ int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req); +/** + * @brief Setup a blocking SPI Target transaction. + * + * The MXC_SPI_Init_v2(..). function must be called before using this transaction + * function. + * + * @param req Pointer to details of the transaction. + * + * @return See \ref MXC_Error_Codes for the list of error return codes. + */ +int MXC_SPI_TargetTransaction(mxc_spi_req_t *req); + +/** + * @brief Setup an interrupt-driven, non-blocking SPI Target transaction. + * + * The MXC_SPI_Init_v2(..). function must be called before using this transaction + * function. + * + * @param req Pointer to details of the transaction. + * + * @return See \ref MXC_Error_Codes for the list of error return codes. + */ +int MXC_SPI_TargetTransactionAsync(mxc_spi_req_t *req); + +/** + * @brief Setup a DMA driven SPI Target transaction. + * + * The MXC_SPI_Init_v2(..). or MXC_SPI_DMA_Init(..). functions must be + * called before calling this DMA transaction function. This function + * does not initialize the DMA. + * + * @param req Pointer to details of the transaction. + * + * @return See \ref MXC_Error_Codes for the list of error return codes. + */ +int MXC_SPI_TargetTransactionDMA(mxc_spi_req_t *req); + /* ** Handler Functions ** */ /** diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_ai87.c b/Libraries/PeriphDrivers/Source/SPI/spi_ai87.c index f33313c1919..70626b81949 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_ai87.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_ai87.c @@ -47,11 +47,18 @@ /* **** Definitions **** */ /* ************************************************************************** */ -int MXC_SPI_Init(mxc_spi_regs_t *spi, int masterMode, int quadModeUsed, int numSlaves, - unsigned ssPolarity, unsigned int hz, mxc_spi_pins_t pins) +int MXC_SPI_Init(mxc_spi_regs_t *spi, mxc_spi_type_t controller_target, mxc_spi_interface_t if_mode, + int numTargets, uint8_t ts_active_pol_mask, uint32_t freq, mxc_spi_pins_t pins) { int spi_num; + // Remap input parameters for v1 implementation. + int masterMode = controller_target; + int quadModeUsed = if_mode; + int numSlaves = numTargets; + int ssPolarity = ts_active_pol_mask; + int hz = freq; + spi_num = MXC_SPI_GET_IDX(spi); MXC_ASSERT(spi_num >= 0); @@ -513,3 +520,141 @@ void MXC_SPI_AsyncHandler(mxc_spi_regs_t *spi) { MXC_SPI_RevA1_AsyncHandler((mxc_spi_reva_regs_t *)spi); } + +/* ** SPI v2 functions to prevent build errors ** */ + +int MXC_SPI_Config(mxc_spi_cfg_t *cfg) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_ConfigStruct(mxc_spi_cfg_t *cfg, bool use_dma_tx, bool use_dma_rx) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_SetTSControl(mxc_spi_regs_t *spi, mxc_spi_tscontrol_t ts_control) +{ + return E_NOT_SUPPORTED; +} + +mxc_spi_tscontrol_t MXC_SPI_GetTSControl(mxc_spi_regs_t *spi) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_SetFrameSize(mxc_spi_regs_t *spi, int frame_size) +{ + return MXC_SPI_SetDataSize(spi, frame_size); +} + +int MXC_SPI_GetFrameSize(mxc_spi_regs_t *spi) +{ + return MXC_SPI_GetDataSize(spi); +} + +int MXC_SPI_SetInterface(mxc_spi_regs_t *spi, mxc_spi_interface_t mode) +{ + return E_NOT_SUPPORTED; +} + +mxc_spi_interface_t MXC_SPI_GetInterface(mxc_spi_regs_t *spi) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_SetClkMode(mxc_spi_regs_t *spi, mxc_spi_clkmode_t clk_mode) +{ + return E_NOT_SUPPORTED; +} + +mxc_spi_clkmode_t MXC_SPI_GetClkMode(mxc_spi_regs_t *spi) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_SetCallback(mxc_spi_regs_t *spi, mxc_spi_callback_t callback, void *data) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_SetDummyTX(mxc_spi_regs_t *spi, uint16_t tx_value) +{ + return MXC_SPI_SetDefaultTXData(spi, tx_value); +} + +/* ** DMA-Specific Functions ** */ + +int MXC_SPI_DMA_Init(mxc_spi_regs_t *spi, mxc_dma_regs_t *dma, bool use_dma_tx, bool use_dma_rx) +{ + return E_NOT_SUPPORTED; +} + +bool MXC_SPI_DMA_GetInitialized(mxc_spi_regs_t *spi) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_DMA_GetTXChannel(mxc_spi_regs_t *spi) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_DMA_GetRXChannel(mxc_spi_regs_t *spi) +{ + return E_NOT_SUPPORTED; +} + +int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, bool use_dma_tx, bool use_dma_rx) +{ + return E_NOT_SUPPORTED; +} + +/* ** Transaction Functions ** */ + +int MXC_SPI_ControllerTransaction(mxc_spi_req_t *req) +{ + return MXC_SPI_MasterTransaction(req); +} + +int MXC_SPI_ControllerTransactionAsync(mxc_spi_req_t *req) +{ + return MXC_SPI_MasterTransactionAsync(req); +} + +int MXC_SPI_ControllerTransactionDMA(mxc_spi_req_t *req) +{ + return MXC_SPI_MasterTransactionDMA(req); +} + +int MXC_SPI_TargetTransaction(mxc_spi_req_t *req) +{ + return MXC_SPI_SlaveTransaction(req); +} + +int MXC_SPI_TargetTransactionAsync(mxc_spi_req_t *req) +{ + return MXC_SPI_SlaveTransactionAsync(req); +} + +int MXC_SPI_TargetTransactionDMA(mxc_spi_req_t *req) +{ + return MXC_SPI_SlaveTransactionDMA(req); +} + +/* ** Handler Functions ** */ + +void MXC_SPI_Handler(mxc_spi_regs_t *spi) +{ + MXC_SPI_AsyncHandler(spi); +} + +void MXC_SPI_DMA_TX_Handler(mxc_spi_regs_t *spi) +{ + return; +} + +void MXC_SPI_DMA_RX_Handler(mxc_spi_regs_t *spi) +{ + return; +} diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c b/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c index 455fb777b4d..857f1363b22 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c @@ -56,275 +56,155 @@ #define MXC_SPI_TS1_MASK_POS (1) #define MXC_SPI_TS2_MASK_POS (2) -// Private variable used to check if DMA is used or not for Init function. -static int use_dma = 0; - -// Private helper function to set up Init struct from legacy implementation. -// Returns Success/Error Codes. -static int MXC_SPI_legacy_setupInit(mxc_spi_init_t *init, mxc_spi_regs_t *spi, int masterMode, - int quadModeUsed, int numSlaves, unsigned ssPolarity, - unsigned int hz, mxc_spi_pins_t pins, bool useDMA) +int MXC_SPI_Init(mxc_spi_regs_t *spi, mxc_spi_type_t controller_target, mxc_spi_interface_t if_mode, + int numTargets, uint8_t ts_active_pol_mask, uint32_t freq, mxc_spi_pins_t pins) { - // Set up init struct. - init->spi = spi; + int error; + int8_t spi_num; + mxc_spi_tscontrol_t ts_control; + mxc_gpio_cfg_t temp_cfg; // main SPI pins. + mxc_gpio_cfg_t temp_ts_cfg; // TS pins. + mxc_gpio_vssel_t vssel; - if (masterMode) { - init->type = MXC_SPI_TYPE_CONTROLLER; // L. Master - } else { - init->type = MXC_SPI_TYPE_TARGET; // L. Slave + spi_num = MXC_SPI_GET_IDX(spi); + if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { + return E_BAD_PARAM; } - init->freq = hz; - - if (quadModeUsed) { - init->mode = MXC_SPI_INTERFACE_QUAD; - } else { - init->mode = MXC_SPI_INTERFACE_STANDARD; + // Check if frequency is too high + if ((spi_num == 0) && (freq > MXC_SPI_GetPeripheralClock(spi))) { + return E_BAD_PARAM; } - // New SPI drivers will not use "mxc_spi_pins_t pins" anymore. - init->spi_pins = NULL; - - // Set up SPI pins like the legacy implementation. - init->ts_control = MXC_SPI_TSCONTROL_HW_AUTO; - init->target.pins = (const mxc_gpio_cfg_t){ 0 }; - init->target.active_polarity = ssPolarity; + if ((spi_num == 1) && (freq > SystemCoreClock)) { + return E_BAD_PARAM; + } - // Set VSSEL level if (pins.vddioh) { - init->vssel = MXC_GPIO_VSSEL_VDDIOH; + vssel = MXC_GPIO_VSSEL_VDDIOH; } else { - init->vssel = MXC_GPIO_VSSEL_VDDIO; - } - - // Set up Target Select pins. - if (pins.ss0) { - init->target.init_mask |= (1 << MXC_SPI_TS0_MASK_POS); // Bit position 0 + vssel = MXC_GPIO_VSSEL_VDDIO; } - if (pins.ss1) { - init->target.init_mask |= (1 << MXC_SPI_TS1_MASK_POS); // Bit position 1 - } - - if (pins.ss2) { - init->target.init_mask |= (1 << MXC_SPI_TS2_MASK_POS); // Bit position 2 - } - - if (pins.sdio2 || pins.sdio3) { - // Ensure QUAD mode is enabled if SDIO2/SDIO3 are true. - if (quadModeUsed == 0) { - return E_BAD_PARAM; - } - } - - // In the previous implementation, the MXC_SPI_Init function does not - // set the message size until later by calling MXC_SPI_SetData. - // By default for the new implementation, the frame_size will be set to 8 bits. - init->frame_size = 8; - - // Set default clock mode (0). - init->clk_mode = MXC_SPI_CLKMODE_0; - - // By default, DMA will be initalized for API function - if (useDMA) { - init->use_dma = true; - init->dma = MXC_DMA; + // SPI Target mode only supports HW_AUTO. + if (pins.ss0 || pins.ss1 || pins.ss2 || (controller_target == MXC_SPI_TYPE_TARGET)) { + ts_control = MXC_SPI_TSCONTROL_HW_AUTO; } else { - init->use_dma = false; - init->dma = NULL; + ts_control = MXC_SPI_TSCONTROL_SW_APP; } - return E_NO_ERROR; -} - -int MXC_SPI_Init(mxc_spi_regs_t *spi, int masterMode, int quadModeUsed, int numSlaves, - unsigned ssPolarity, unsigned int hz, mxc_spi_pins_t pins) -{ - int error, spi_num; - - // TODO(5-15-2023): Remove this section when the Init function is updated to - // int MXC_SPI_Init(mxc_spi_init_t *init) - // This function is for backwards compatibility, before fully updating to new - // implementation. - mxc_spi_init_t spi_init = (const mxc_spi_init_t){ 0 }; - mxc_spi_init_t *init = &spi_init; - - error = MXC_SPI_legacy_setupInit(init, spi, masterMode, quadModeUsed, numSlaves, ssPolarity, hz, - pins, use_dma); + error = MXC_SPI_RevA2_SetTSControl((mxc_spi_reva_regs_t *)spi, ts_control); if (error != E_NO_ERROR) { return error; } - spi_num = MXC_SPI_GET_IDX(init->spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - // Check if frequency is too high - if ((spi_num == 0) && (init->freq > MXC_SPI_GetPeripheralClock(init->spi))) { - return E_BAD_PARAM; - } - - if ((spi_num == 1) && (init->freq > SystemCoreClock)) { - return E_BAD_PARAM; - } - - // Note: Target Select (L. SS) Pins will be configured in MXC_SPI_RevA2_Init. - // Configure GPIO for spi - if (init->spi == MXC_SPI1) { + // Configure SPI peripheral and pins. + if (spi == MXC_SPI1) { MXC_SYS_Reset_Periph(MXC_SYS_RESET0_SPI1); MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_SPI1); - // Configure SPI to default pins if not provided. - if (init->spi_pins == NULL) { - if (init->mode == MXC_SPI_INTERFACE_3WIRE) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_3wire); - - } else if (init->mode == MXC_SPI_INTERFACE_STANDARD) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_standard); + switch (if_mode) { + case MXC_SPI_INTERFACE_STANDARD: + temp_cfg = gpio_cfg_spi1_standard; + break; - } else if (init->mode == MXC_SPI_INTERFACE_DUAL) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_dual); + case MXC_SPI_INTERFACE_QUAD: + temp_cfg = gpio_cfg_spi1_quad; + break; - } else if (init->mode == MXC_SPI_INTERFACE_QUAD) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_quad); + case MXC_SPI_INTERFACE_3WIRE: + temp_cfg = gpio_cfg_spi1_3wire; + break; - } else { - return E_BAD_PARAM; - } + case MXC_SPI_INTERFACE_DUAL: + temp_cfg = gpio_cfg_spi1_dual; + break; - } else { - error = MXC_GPIO_Config(init->spi_pins); + default: + return E_BAD_PARAM; } - // Ensure SPI GPIO pins were properly configured. - if (error != E_NO_ERROR) { - return error; + // Set up HW TS pins (if HW_AUTO TS control scheme was selected). + // Voltage and drive strength settings will match the SPI pins. + if (ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { + // Target Select 0 - TS0 (L. SS0 pin) + if (pins.ss0 == true) { + temp_ts_cfg = gpio_cfg_spi1_ts0; + temp_ts_cfg.vssel = vssel; + temp_ts_cfg.drvstr = pins.drvstr; + + error = MXC_GPIO_Config(&temp_ts_cfg); + if (error != E_NO_ERROR) { + return error; + } + } } -// Handles RISCV SPI Numbering. +// Handle RISCV SPI instance numbering. #ifdef MXC_SPI0 - } else if (init->spi == MXC_SPI0) { + } else if (spi == MXC_SPI0) { MXC_SYS_Reset_Periph(MXC_SYS_RESET1_SPI0); MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_SPI0); - // Configure SPI to default pins if not provided. - if (init->spi_pins == NULL) { - if (init->mode == MXC_SPI_INTERFACE_3WIRE) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_3wire); - - } else if (init->mode == MXC_SPI_INTERFACE_STANDARD) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_standard); - - } else if (init->mode == MXC_SPI_INTERFACE_DUAL) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_dual); + switch (if_mode) { + case MXC_SPI_INTERFACE_STANDARD: + temp_cfg = gpio_cfg_spi0_standard; + break; - } else if (init->mode == MXC_SPI_INTERFACE_QUAD) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_quad); + case MXC_SPI_INTERFACE_QUAD: + temp_cfg = gpio_cfg_spi0_quad; + break; - } else { - return E_BAD_PARAM; - } + case MXC_SPI_INTERFACE_3WIRE: + temp_cfg = gpio_cfg_spi0_3wire; + break; - } else { - error = MXC_GPIO_Config(init->spi_pins); - } + case MXC_SPI_INTERFACE_DUAL: + temp_cfg = gpio_cfg_spi0_dual; + break; - // Ensure SPI GPIO pins were properly configured. - if (error != E_NO_ERROR) { - return error; + default: + return E_BAD_PARAM; } -#endif - - } else { - return E_NO_DEVICE; - } - - return MXC_SPI_RevA2_Init(init); -} - -int MXC_SPI_Init_v2(mxc_spi_init_t *init) -{ - int error, spi_num; - - spi_num = MXC_SPI_GET_IDX(init->spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - // Check if frequency is too high - if ((spi_num == 0) && (init->freq > MXC_SPI_GetPeripheralClock(init->spi))) { - return E_BAD_PARAM; - } - - if ((spi_num == 1) && (init->freq > SystemCoreClock)) { - return E_BAD_PARAM; - } - - // Note: Target Select (L. SS) Pins will be configured in MXC_SPI_RevA2_Init. - // Configure GPIO for spi - if (init->spi == MXC_SPI1) { - MXC_SYS_Reset_Periph(MXC_SYS_RESET0_SPI1); - MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_SPI1); - - // Configure SPI to default pins if not provided. - if (init->spi_pins == NULL) { - if (init->mode == MXC_SPI_INTERFACE_3WIRE) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_3wire); - - } else if (init->mode == MXC_SPI_INTERFACE_STANDARD) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_standard); - - } else if (init->mode == MXC_SPI_INTERFACE_DUAL) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_dual); - } else if (init->mode == MXC_SPI_INTERFACE_QUAD) { - error = MXC_GPIO_Config(&gpio_cfg_spi1_quad); - - } else { - return E_BAD_PARAM; + // Set up HW TS pins (if HW_AUTO TS control scheme was selected). + // Voltage and drive strength settings will match the SPI pins. + if (ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { + // Target Select 0 - TS0 (L. SS0 pin) + if (pins.ss0 == true) { + temp_ts_cfg = gpio_cfg_spi0_ts0; + temp_ts_cfg.vssel = vssel; + temp_ts_cfg.drvstr = pins.drvstr; + + error = MXC_GPIO_Config(&temp_ts_cfg); + if (error != E_NO_ERROR) { + return error; + } } - } else { - error = MXC_GPIO_Config(init->spi_pins); - } - - // Ensure SPI GPIO pins were properly configured. - if (error != E_NO_ERROR) { - return error; - } + // Target Select 1 - TS1 (L. SS1 pin) + if (pins.ss1 == true) { + temp_ts_cfg = gpio_cfg_spi0_ts1; + temp_ts_cfg.vssel = vssel; + temp_ts_cfg.drvstr = pins.drvstr; -// Handles RISCV SPI Numbering. -#ifdef MXC_SPI0 - } else if (init->spi == MXC_SPI0) { - MXC_SYS_Reset_Periph(MXC_SYS_RESET1_SPI0); - MXC_SYS_ClockEnable(MXC_SYS_PERIPH_CLOCK_SPI0); - - // Configure SPI to default pins if not provided. - if (init->spi_pins == NULL) { - if (init->mode == MXC_SPI_INTERFACE_3WIRE) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_3wire); - - } else if (init->mode == MXC_SPI_INTERFACE_STANDARD) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_standard); - - } else if (init->mode == MXC_SPI_INTERFACE_DUAL) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_dual); - - } else if (init->mode == MXC_SPI_INTERFACE_QUAD) { - error = MXC_GPIO_Config(&gpio_cfg_spi0_quad); - - } else { - return E_BAD_PARAM; + error = MXC_GPIO_Config(&temp_ts_cfg); + if (error != E_NO_ERROR) { + return error; + } } - } else { - error = MXC_GPIO_Config(init->spi_pins); - } + // Target Select 2 - TS2 (L. SS2 pin) + if (pins.ss2 == true) { + temp_ts_cfg = gpio_cfg_spi0_ts2; + temp_ts_cfg.vssel = vssel; + temp_ts_cfg.drvstr = pins.drvstr; - // Ensure SPI GPIO pins were properly configured. - if (error != E_NO_ERROR) { - return error; + error = MXC_GPIO_Config(&temp_ts_cfg); + if (error != E_NO_ERROR) { + return error; + } + } } #endif @@ -332,56 +212,49 @@ int MXC_SPI_Init_v2(mxc_spi_init_t *init) return E_NO_DEVICE; } - return MXC_SPI_RevA2_Init(init); -} + temp_cfg.vssel = vssel; + temp_cfg.drvstr = pins.drvstr; -int MXC_SPI_InitStruct(mxc_spi_init_t *init) -{ - if (init == NULL) { - return E_BAD_PARAM; + // Configure main SPI pins. + error = MXC_GPIO_Config(&temp_cfg); + if (error != E_NO_ERROR) { + return error; } - init->spi = MXC_SPI1; // SPI1 is available on both the ARM and RISCV core. - init->spi_pins = NULL; // Use default, predefined pins - init->type = MXC_SPI_TYPE_CONTROLLER; // Controller mode - init->freq = 100000; // 100KHz - init->clk_mode = MXC_SPI_CLKMODE_0; // 0 - CPOL :: 0 - CPHA - init->mode = MXC_SPI_INTERFACE_STANDARD; // Standard 4-wire mode - init->ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // Automatic Hardware Driven TS Control - init->target.active_polarity = 0; // Active polarity is LOW (0). IDLE is HIGH (1). - init->vssel = MXC_GPIO_VSSEL_VDDIO; // VDDIO - 1.8V - init->target.init_mask = 0x01; // Default TS0 - init->use_dma = false; // DMA not used - init->dma = NULL; + return MXC_SPI_RevA2_Init((mxc_spi_reva_regs_t *)spi, controller_target, if_mode, freq, + ts_active_pol_mask); +} - return E_SUCCESS; +int MXC_SPI_Config(mxc_spi_cfg_t *cfg) +{ + return MXC_SPI_RevA2_Config(cfg); } -int MXC_SPI_InitStruct_DMA(mxc_spi_init_t *init) +int MXC_SPI_ConfigStruct(mxc_spi_cfg_t *cfg, bool use_dma_tx, bool use_dma_rx) { - if (init == NULL) { + if (cfg == NULL) { return E_BAD_PARAM; } - init->spi = MXC_SPI1; // SPI1 is available on both the ARM and RISCV core. - init->spi_pins = NULL; // Use default, predefined pins - init->type = MXC_SPI_TYPE_CONTROLLER; // Controller mode - init->freq = 100000; // 100KHz - init->clk_mode = MXC_SPI_CLKMODE_0; // 0 - CPOL :: 0 - CPHA - init->mode = MXC_SPI_INTERFACE_STANDARD; // Standard 4-wire mode - init->ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // Automatic Hardware Driven TS Control - init->target.active_polarity = 0; // Active polarity is LOW (0), IDLE is HIGH (1) - init->vssel = MXC_GPIO_VSSEL_VDDIO; // VDDIO - 1.8V - init->target.init_mask = 0x01; // Default TS0 - init->use_dma = true; // Use DMA - init->dma = MXC_DMA; + cfg->spi = MXC_SPI1; // SPI1 is available on both the ARM and RISCV core. + cfg->clk_mode = MXC_SPI_CLKMODE_0; // 0 - CPOL :: 0 - CPHA + + if (use_dma_tx || use_dma_rx) { + cfg->use_dma_tx = use_dma_tx; + cfg->use_dma_rx = use_dma_rx; + cfg->dma = MXC_DMA; + } else { + cfg->use_dma_tx = false; + cfg->use_dma_rx = false; + cfg->dma = NULL; + } return E_SUCCESS; } int MXC_SPI_Shutdown(mxc_spi_regs_t *spi) { - int spi_num; + int8_t spi_num; spi_num = MXC_SPI_GET_IDX(spi); if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { @@ -465,95 +338,14 @@ int MXC_SPI_GetPeripheralClock(mxc_spi_regs_t *spi) return retval; } -int MXC_SPI_ConfigTargetSelect(mxc_spi_regs_t *spi, uint32_t index, mxc_gpio_vssel_t vssel) +int MXC_SPI_SetTSControl(mxc_spi_regs_t *spi, mxc_spi_tscontrol_t ts_control) { - int error, spi_num; - - spi_num = MXC_SPI_GET_IDX(spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - if (spi == MXC_SPI1) { - if (index > MXC_SPI1_TS_INSTANCES) { - return E_BAD_PARAM; - } - - switch (index) { - // Target Select 0 - TS0 (L. SS0 pin) - case 0: - error = MXC_GPIO_Config(&gpio_cfg_spi1_ts0); - if (error != E_NO_ERROR) { - return error; - } - - error = MXC_GPIO_SetVSSEL(gpio_cfg_spi1_ts0.port, vssel, gpio_cfg_spi1_ts0.mask); - if (error != E_NO_ERROR) { - return error; - } - - break; - - default: - return E_BAD_PARAM; - } - -#ifdef MXC_SPI0 - } else if (spi == MXC_SPI0) { - if (index > MXC_SPI0_TS_INSTANCES) { - return E_BAD_PARAM; - } - - switch (index) { - // Target Select 0 - TS0 (L. SS0 pin) - case 0: - error = MXC_GPIO_Config(&gpio_cfg_spi0_ts0); - if (error != E_NO_ERROR) { - return error; - } - - error = MXC_GPIO_SetVSSEL(gpio_cfg_spi0_ts0.port, vssel, gpio_cfg_spi0_ts0.mask); - if (error != E_NO_ERROR) { - return error; - } - - break; - - // Target Select 1 - TS1 (L. SS1 pin) - case 1: - error = MXC_GPIO_Config(&gpio_cfg_spi0_ts1); - if (error != E_NO_ERROR) { - return error; - } - - error = MXC_GPIO_SetVSSEL(gpio_cfg_spi0_ts1.port, vssel, gpio_cfg_spi0_ts1.mask); - if (error != E_NO_ERROR) { - return error; - } - - break; - - // Target Select 2 (TS2 - L. SS2 pin) - case 2: - error = MXC_GPIO_Config(&gpio_cfg_spi0_ts2); - if (error != E_NO_ERROR) { - return error; - } - - error = MXC_GPIO_SetVSSEL(gpio_cfg_spi0_ts2.port, vssel, gpio_cfg_spi0_ts2.mask); - if (error != E_NO_ERROR) { - return error; - } - - break; - - default: - return E_BAD_PARAM; - } -#endif - } + return MXC_SPI_RevA2_SetTSControl((mxc_spi_reva_regs_t *)spi, ts_control); +} - return E_NO_ERROR; +mxc_spi_tscontrol_t MXC_SPI_GetTSControl(mxc_spi_regs_t *spi) +{ + return MXC_SPI_RevA2_GetTSControl((mxc_spi_reva_regs_t *)spi); } int MXC_SPI_SetFrequency(mxc_spi_regs_t *spi, unsigned int hz) @@ -596,9 +388,9 @@ mxc_spi_clkmode_t MXC_SPI_GetClkMode(mxc_spi_regs_t *spi) return MXC_SPI_RevA2_GetClkMode((mxc_spi_reva_regs_t *)spi); } -int MXC_SPI_SetCallback(mxc_spi_regs_t *spi, mxc_spi_callback_t callback, void *data) +int MXC_SPI_SetCallback(mxc_spi_regs_t *spi, mxc_spi_callback_t completeCB, void *data) { - return MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)spi, callback, data); + return MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)spi, completeCB, data); } int MXC_SPI_GetActive(mxc_spi_regs_t *spi) @@ -668,9 +460,10 @@ unsigned int MXC_SPI_GetRXThreshold(mxc_spi_regs_t *spi) /* ** DMA-Specific Functions ** */ -int MXC_SPI_DMA_Init(mxc_spi_init_t *init) +int MXC_SPI_DMA_Init(mxc_spi_regs_t *spi, mxc_dma_regs_t *dma, bool use_dma_tx, bool use_dma_rx) { - return MXC_SPI_RevA2_DMA_Init(init); + return MXC_SPI_RevA2_DMA_Init((mxc_spi_reva_regs_t *)spi, (mxc_dma_reva_regs_t *)dma, + use_dma_tx, use_dma_rx); } bool MXC_SPI_DMA_GetInitialized(mxc_spi_regs_t *spi) @@ -688,9 +481,9 @@ int MXC_SPI_DMA_GetRXChannel(mxc_spi_regs_t *spi) return MXC_SPI_RevA2_DMA_GetRXChannel((mxc_spi_reva_regs_t *)spi); } -int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint8_t *rx_buffer) +int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, bool use_dma_tx, bool use_dma_rx) { - int spi_num; + int8_t spi_num; int tx_reqsel = -1; int rx_reqsel = -1; @@ -699,7 +492,7 @@ int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint8_ return E_INVALID; } - if (tx_buffer != NULL) { + if (use_dma_tx) { switch (spi_num) { case 0: tx_reqsel = MXC_DMA_REQUEST_SPI1TX; @@ -714,7 +507,7 @@ int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint8_ } } - if (rx_buffer != NULL) { + if (use_dma_rx) { switch (spi_num) { case 0: rx_reqsel = MXC_DMA_REQUEST_SPI1RX; @@ -736,142 +529,158 @@ int MXC_SPI_DMA_SetRequestSelect(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint8_ int MXC_SPI_MasterTransaction(mxc_spi_req_t *req) { - mxc_spi_target_t target; - - // For backwards-compatibility with previous SPI implementation, use - // use the req->ts_idx (L. req->ssIdx) as default. - // Note: the previous implementation did not have an option to select - // targets for transactions. - target.index = req->ts_idx; // also req->ssIdx - - // Mainly used if MXC_SPI_TSCONTROL_SW_DRV scheme was selected. - target.pins = req->target_sel.pins; - target.active_polarity = req->target_sel.active_polarity; - - return MXC_SPI_RevA2_ControllerTransactionB((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, - req->tx_len, req->rx_buffer, req->rx_len, - req->deassert, &target); + return MXC_SPI_RevA2_ControllerTransaction((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, req->ssDeassert, + req->ssIdx); } int MXC_SPI_MasterTransactionAsync(mxc_spi_req_t *req) { int error; - mxc_spi_target_t target; - - // For backwards-compatibility with previous SPI implementation, use - // use the req->ts_idx (L. req->ssIdx) as default. - // Note: the previous implementation did not have an option to select - // targets for transactions. - target.index = req->ts_idx; // also req->ssIdx - - // Mainly used if MXC_SPI_TSCONTROL_SW_DRV scheme was selected. - target.pins = req->target_sel.pins; - target.active_polarity = req->target_sel.active_polarity; - error = MXC_SPI_SetCallback(req->spi, req->callback, req->callback_data); - if (error != E_NO_ERROR) { - return error; + // Users can set their own callback and pass in their own data if they choose to. + if (req->completeCB != NULL) { + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } } - return MXC_SPI_RevA2_ControllerTransaction((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, - req->tx_len, req->rx_buffer, req->rx_len, - req->deassert, &target); + return MXC_SPI_RevA2_ControllerTransactionAsync((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, + req->ssDeassert, req->ssIdx); } int MXC_SPI_MasterTransactionDMA(mxc_spi_req_t *req) { int error; - mxc_spi_target_t target; - mxc_spi_init_t init; - // For backwards-compatibility with previous SPI implementation, use - // use the req->ts_idx (L. req->ssIdx) as default. - // Note: the previous implementation did not have an option to select - // targets for transactions. - target.index = req->ts_idx; // also req->ssIdx + // Users can set their own callback and pass in their own data if they choose to. + if (req->completeCB != NULL) { + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } + } + + return MXC_SPI_RevA2_ControllerTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, + req->ssDeassert, req->ssIdx, + (mxc_dma_reva_regs_t *)MXC_DMA); +} - // Mainly used if MXC_SPI_TSCONTROL_SW_DRV scheme was selected. - target.pins = req->target_sel.pins; - target.active_polarity = req->target_sel.active_polarity; +int MXC_SPI_ControllerTransaction(mxc_spi_req_t *req) +{ + return MXC_SPI_RevA2_ControllerTransaction((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, req->ssDeassert, + req->ssIdx); +} - init.use_dma = true; - init.dma = MXC_DMA; +int MXC_SPI_ControllerTransactionAsync(mxc_spi_req_t *req) +{ + int error; - // More overhead, but this function will initalize DMA if not initialized. - if (MXC_SPI_DMA_GetInitialized(req->spi) == false) { - error = MXC_SPI_DMA_Init(&init); + // Users can set their own callback and pass in their own data if they choose to. + if (req->completeCB != NULL) { + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); if (error != E_NO_ERROR) { return error; } } - error = MXC_SPI_SetCallback(req->spi, req->callback, req); - if (error != E_NO_ERROR) { - return error; - } + return MXC_SPI_RevA2_ControllerTransactionAsync((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, + req->ssDeassert, req->ssIdx); +} - error = MXC_SPI_DMA_SetRequestSelect(req->spi, req->tx_buffer, req->rx_buffer); - if (error != E_NO_ERROR) { - return error; +int MXC_SPI_ControllerTransactionDMA(mxc_spi_req_t *req) +{ + int error; + + // Users can set their own callback and pass in their own data if they choose to. + if (req->completeCB != NULL) { + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } } - return MXC_SPI_RevA2_ControllerTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, - req->tx_len, req->rx_buffer, req->rx_len, - req->deassert, &target); + return MXC_SPI_RevA2_ControllerTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, + req->ssDeassert, req->ssIdx, + (mxc_dma_reva_regs_t *)MXC_DMA); } -int MXC_SPI_ControllerTransaction(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target) +int MXC_SPI_SlaveTransaction(mxc_spi_req_t *req) { - return MXC_SPI_RevA2_ControllerTransaction((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, - rx_buffer, rx_fr_len, deassert, target); + return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen); } -int MXC_SPI_ControllerTransactionB(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target) +int MXC_SPI_SlaveTransactionAsync(mxc_spi_req_t *req) { - return MXC_SPI_RevA2_ControllerTransactionB((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, - rx_buffer, rx_fr_len, deassert, target); + int error; + + // Users can set their own callback and pass in their own data if they choose to. + if (req->completeCB != NULL) { + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } + } + + return MXC_SPI_RevA2_TargetTransactionAsync((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen); } -int MXC_SPI_ControllerTransactionDMA(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target) +int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req) { int error; - error = MXC_SPI_DMA_SetRequestSelect(spi, tx_buffer, rx_buffer); - if (error != E_NO_ERROR) { - return error; + // Users can set their own callback and pass in their own data if they choose to. + if (req->completeCB != NULL) { + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } } - return MXC_SPI_RevA2_ControllerTransactionDMA((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, - rx_buffer, rx_fr_len, deassert, target); + return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, + (mxc_dma_reva_regs_t *)MXC_DMA); } -int MXC_SPI_ControllerTransactionDMAB(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32_t tx_fr_len, - uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target) +int MXC_SPI_TargetTransaction(mxc_spi_req_t *req) { - return MXC_SPI_RevA2_ControllerTransactionDMAB((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, - rx_buffer, rx_fr_len, deassert, target); + return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen); } -int MXC_SPI_SlaveTransaction(mxc_spi_req_t *req) +int MXC_SPI_TargetTransactionAsync(mxc_spi_req_t *req) { - return E_NOT_SUPPORTED; -} + int error; -int MXC_SPI_SlaveTransactionAsync(mxc_spi_req_t *req) -{ - return E_NOT_SUPPORTED; + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } + + return MXC_SPI_RevA2_TargetTransactionAsync((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen); } -int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req) +int MXC_SPI_TargetTransactionDMA(mxc_spi_req_t *req) { - return E_NOT_SUPPORTED; + int error; + + error = MXC_SPI_RevA2_SetCallback((mxc_spi_reva_regs_t *)(req->spi), req->completeCB, req); + if (error != E_NO_ERROR) { + return error; + } + + return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->txData, + req->txLen, req->rxData, req->rxLen, + (mxc_dma_reva_regs_t *)MXC_DMA); } /* ** Handler Functions ** */ @@ -931,11 +740,11 @@ int MXC_SPI_SetWidth(mxc_spi_regs_t *spi, mxc_spi_width_t spiWidth) mxc_spi_width_t MXC_SPI_GetWidth(mxc_spi_regs_t *spi) { - mxc_spi_interface_t mode; + mxc_spi_interface_t if_mode; - mode = MXC_SPI_GetInterface(spi); + if_mode = MXC_SPI_GetInterface(spi); - switch (mode) { + switch (if_mode) { case MXC_SPI_INTERFACE_STANDARD: return SPI_WIDTH_STANDARD; @@ -975,13 +784,13 @@ int MXC_SPI_SetMode(mxc_spi_regs_t *spi, mxc_spi_mode_t spiMode) return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_0); case SPI_MODE_1: - return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_0); + return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_1); case SPI_MODE_2: - return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_0); + return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_2); case SPI_MODE_3: - return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_0); + return MXC_SPI_SetClkMode(spi, MXC_SPI_CLKMODE_3); default: return E_BAD_PARAM; diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_reva1.c b/Libraries/PeriphDrivers/Source/SPI/spi_reva1.c index c631757a245..0eb5617b086 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva1.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva1.c @@ -530,22 +530,22 @@ unsigned int MXC_SPI_RevA1_ReadRXFIFO(mxc_spi_reva_regs_t *spi, unsigned char *b len &= ~(unsigned)0x1; } - unsigned cnt = 0; + unsigned count = 0; if (bits <= 8 || len >= 2) { // Read from the FIFO while (len) { if (len > 3) { - memcpy((uint8_t *)(&bytes[cnt]), (void *)(&spi->fifo32), 4); + memcpy((uint8_t *)(&bytes[count]), (void *)(&spi->fifo32), 4); len -= 4; - cnt += 4; + count += 4; } else if (len > 1) { - memcpy((uint8_t *)(&bytes[cnt]), (void *)(&spi->fifo16[0]), 2); + memcpy((uint8_t *)(&bytes[count]), (void *)(&spi->fifo16[0]), 2); len -= 2; - cnt += 2; + count += 2; } else { - ((uint8_t *)bytes)[cnt++] = spi->fifo8[0]; + ((uint8_t *)bytes)[count++] = spi->fifo8[0]; len -= 1; } @@ -556,7 +556,7 @@ unsigned int MXC_SPI_RevA1_ReadRXFIFO(mxc_spi_reva_regs_t *spi, unsigned char *b } } - return cnt; + return count; } unsigned int MXC_SPI_RevA1_GetRXFIFOAvailable(mxc_spi_reva_regs_t *spi) @@ -584,28 +584,28 @@ unsigned int MXC_SPI_RevA1_WriteTXFIFO(mxc_spi_reva_regs_t *spi, unsigned char * len &= ~(unsigned)0x1; } - unsigned cnt = 0; + unsigned count = 0; while (len) { if (len > 3) { - memcpy((void *)(&spi->fifo32), (uint8_t *)(&bytes[cnt]), 4); + memcpy((void *)(&spi->fifo32), (uint8_t *)(&bytes[count]), 4); len -= 4; - cnt += 4; + count += 4; } else if (len > 1) { - memcpy((void *)(&spi->fifo16[0]), (uint8_t *)(&bytes[cnt]), 2); + memcpy((void *)(&spi->fifo16[0]), (uint8_t *)(&bytes[count]), 2); len -= 2; - cnt += 2; + count += 2; } else if (bits <= 8) { - spi->fifo8[0] = ((uint8_t *)bytes)[cnt++]; + spi->fifo8[0] = ((uint8_t *)bytes)[count++]; len--; } } - return cnt; + return count; } unsigned int MXC_SPI_RevA1_GetTXFIFOAvailable(mxc_spi_reva_regs_t *spi) @@ -770,7 +770,9 @@ uint32_t MXC_SPI_RevA1_MasterTransHandler(mxc_spi_reva_regs_t *spi, mxc_spi_reva // Leave slave select asserted at the end of the transaction if (states[spi_num].hw_ss_control && !req->ssDeassert) { - spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_SS_CTRL; + spi->ctrl0 = (spi->ctrl0 & ~MXC_F_SPI_REVA_CTRL0_START) | MXC_F_SPI_REVA_CTRL0_SS_CTRL; + // Note: Setting 0 to START bit to avoid race condition and duplicated starts. + // See https://github.com/Analog-Devices-MSDK/msdk/issues/713 } retval = MXC_SPI_RevA1_TransHandler(spi, req); @@ -782,7 +784,7 @@ uint32_t MXC_SPI_RevA1_MasterTransHandler(mxc_spi_reva_regs_t *spi, mxc_spi_reva // Deassert slave select at the end of the transaction if (states[spi_num].hw_ss_control && req->ssDeassert) { - spi->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_SS_CTRL; + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_START | MXC_F_SPI_REVA_CTRL0_SS_CTRL); } return retval; diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c index 8f6b87e7307..69421b11333 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c @@ -51,25 +51,27 @@ // clang-format off typedef struct { // Info from initialization. - bool initialized; bool dma_initialized; - mxc_spi_init_t init; + mxc_spi_type_t controller_target; // Controller or Target Mode. + uint8_t frame_size; // + mxc_spi_interface_t if_mode; + // Transaction Data. uint8_t *tx_buffer; - uint32_t tx_len; // Terms of bytes - uint32_t tx_cnt; // Terms of bytes + uint32_t tx_length_bytes; // Terms of bytes + uint32_t tx_count_bytes; // Terms of bytes uint8_t *rx_buffer; - uint32_t rx_len; // Terms of bytes - uint32_t rx_cnt; + uint32_t rx_length_bytes; // Terms of bytes + uint32_t rx_count_bytes; uint16_t tx_dummy_value; mxc_spi_callback_t callback; void *callback_data; // Chip Select Info. - bool deassert; // Target Select (TS) Deasserted at the end of a transmission. - mxc_spi_target_t current_target; + bool deassert; // Target Select (TS) Deasserted at the end of a transmission. + mxc_spi_tscontrol_t ts_control; // DMA Settings. mxc_dma_reva_regs_t *dma; @@ -77,14 +79,13 @@ typedef struct { int rx_dma_ch; // Status Fields. - bool controller_done; // Master - bool target_done; // Slave + bool transaction_done; bool tx_done; bool rx_done; -} mxc_spi_handle_data_t; +} mxc_spi_reva2_handle_data_t; // clang-format on -static volatile mxc_spi_handle_data_t STATES[MXC_SPI_INSTANCES]; +static volatile mxc_spi_reva2_handle_data_t STATES[MXC_SPI_INSTANCES]; /* **** Private Functions **** */ @@ -95,23 +96,19 @@ static volatile mxc_spi_handle_data_t STATES[MXC_SPI_INSTANCES]; * This function helps package the frame when the STATES[n] fields * are all in terms of bytes. * - * @param spi Pointer to SPI instance. - * @param buffer Pointer to buffer of messages to transmit. - * @param len_bytes Number of messages (in terms of bytes) in buffer to transmit. + * @param spi Pointer to SPI instance. + * @param buffer Pointer to buffer of messages to transmit. + * @param length_bytes Number of messages (in terms of bytes) in buffer to transmit. * - * @return cnt The number of frames written to the TX FIFO. + * @return count The number of frames written to the TX FIFO. */ static uint32_t MXC_SPI_RevA2_writeTXFIFO16(mxc_spi_reva_regs_t *spi, uint8_t *buffer, - uint32_t len_bytes) + uint32_t length_bytes) { uint32_t tx_avail; - int spi_num; - uint32_t cnt = 0; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); + uint32_t count = 0; - if (buffer == NULL || len_bytes == 0) { + if (buffer == NULL || length_bytes == 0) { return 0; } @@ -119,31 +116,31 @@ static uint32_t MXC_SPI_RevA2_writeTXFIFO16(mxc_spi_reva_regs_t *spi, uint8_t *b ((spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) >> MXC_F_SPI_REVA_DMA_TX_LVL_POS); // Do not write more than the available FIFO size - if (len_bytes > tx_avail) { - len_bytes = tx_avail; + if (length_bytes > tx_avail) { + length_bytes = tx_avail; } // Ensure even lengths for halfword frame lengths. // Note: Len is in terms of bytes, so sending 9-16bit transactions means sending // 2 bytes per frame. - len_bytes &= ~0x01; + length_bytes &= ~0x01; - while (len_bytes) { - if (len_bytes > 3) { - memcpy((void *)(&spi->fifo32), (uint8_t *)(&buffer[cnt]), 4); + while (length_bytes) { + if (length_bytes > 3) { + memcpy((void *)(&spi->fifo32), (uint8_t *)(&buffer[count]), 4); - len_bytes -= 4; - cnt += 4; + length_bytes -= 4; + count += 4; - } else if (len_bytes > 1) { - memcpy((void *)(&spi->fifo16[0]), (uint8_t *)(&buffer[cnt]), 2); + } else if (length_bytes > 1) { + memcpy((void *)(&spi->fifo16[0]), (uint8_t *)(&buffer[count]), 2); - len_bytes -= 2; - cnt += 2; + length_bytes -= 2; + count += 2; } } - return cnt; + return count; } /** Private Function: readRXFIFO16 @@ -151,61 +148,57 @@ static uint32_t MXC_SPI_RevA2_writeTXFIFO16(mxc_spi_reva_regs_t *spi, uint8_t *b * This function helps package the frame when the STATES[n] fields * are all in terms of bytes. * - * @param spi Pointer to SPI instance. - * @param buffer Pointer to buffer to store read messages. - * @param len_bytes Number of messages (in terms of bytes) to store in receive buffer. + * @param spi Pointer to SPI instance. + * @param buffer Pointer to buffer to store read messages. + * @param length_bytes Number of messages (in terms of bytes) to store in receive buffer. * - * @return cnt The number of frames read from the RX FIFO + * @return count The number of frames read from the RX FIFO. */ static uint32_t MXC_SPI_RevA2_readRXFIFO16(mxc_spi_reva_regs_t *spi, uint8_t *buffer, - uint32_t len_bytes) + uint32_t length_bytes) { uint32_t rx_avail; - int spi_num; - uint32_t cnt = 0; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); + uint32_t count = 0; - if (buffer == NULL || len_bytes == 0) { + if (buffer == NULL || length_bytes == 0) { return 0; } rx_avail = (spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL) >> MXC_F_SPI_REVA_DMA_RX_LVL_POS; // Do not read more than available frames in RX FIFO. - if (len_bytes > rx_avail) { - len_bytes = rx_avail; + if (length_bytes > rx_avail) { + length_bytes = rx_avail; } // Ensure even lengths for halfword frame lengths. // Note: Len is in terms of bytes, so reading 9-16bit wide messages means reading // 2 bytes per frame. - len_bytes &= ~0x01; + length_bytes &= ~0x01; - if (len_bytes >= 2) { + if (length_bytes >= 2) { // Read from the FIFO - while (len_bytes) { - if (len_bytes > 3) { - memcpy((uint8_t *)(&buffer[cnt]), (void *)(&spi->fifo32), 4); - len_bytes -= 4; - cnt += 4; - - } else if (len_bytes > 1) { - memcpy((uint8_t *)(&buffer[cnt]), (void *)(&spi->fifo16[0]), 2); - len_bytes -= 2; - cnt += 2; + while (length_bytes) { + if (length_bytes > 3) { + memcpy((uint8_t *)(&buffer[count]), (void *)(&spi->fifo32), 4); + length_bytes -= 4; + count += 4; + + } else if (length_bytes > 1) { + memcpy((uint8_t *)(&buffer[count]), (void *)(&spi->fifo16[0]), 2); + length_bytes -= 2; + count += 2; } // Ensures read of less than 2 bytes aren't read. // Code should never get to this point. - if (len_bytes == 1) { + if (length_bytes == 1) { break; } } } - return cnt; + return count; } /** Private Function: process @@ -215,30 +208,34 @@ static uint32_t MXC_SPI_RevA2_readRXFIFO16(mxc_spi_reva_regs_t *spi, uint8_t *bu */ static void MXC_SPI_RevA2_process(mxc_spi_reva_regs_t *spi) { - int spi_num; + int8_t spi_num; int remain; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); // Write any pending bytes out. // Dependent on 1) Valid TX Buffer, 2) TX Length not 0, and 3) TX FIFO Not Empty. - if (STATES[spi_num].tx_buffer && STATES[spi_num].tx_len > 0) { + if (STATES[spi_num].tx_buffer && STATES[spi_num].tx_length_bytes > 0) { // Write to the FIFO for byte size transactions (message sizes for 8 bits or less) - if (STATES[spi_num].init.frame_size <= 8) { + if (STATES[spi_num].frame_size <= 8) { while (((spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) >> MXC_F_SPI_REVA_DMA_TX_LVL_POS) < (MXC_SPI_FIFO_DEPTH)) { - spi->fifo8[0] = STATES[spi_num].tx_buffer[STATES[spi_num].tx_cnt]; - STATES[spi_num].tx_cnt += 1; + // Check for overflow. + if (STATES[spi_num].tx_count_bytes == STATES[spi_num].tx_length_bytes) { + break; + } + + spi->fifo8[0] = STATES[spi_num].tx_buffer[STATES[spi_num].tx_count_bytes]; + STATES[spi_num].tx_count_bytes += 1; } // Write to the FIFO for halfword size transactions (message sizes for 9 bits or greater) } else { - STATES[spi_num].tx_cnt += MXC_SPI_RevA2_writeTXFIFO16( - spi, &(STATES[spi_num].tx_buffer[STATES[spi_num].tx_cnt]), - STATES[spi_num].tx_len - STATES[spi_num].tx_cnt); + STATES[spi_num].tx_count_bytes += MXC_SPI_RevA2_writeTXFIFO16( + spi, &(STATES[spi_num].tx_buffer[STATES[spi_num].tx_count_bytes]), + STATES[spi_num].tx_length_bytes - STATES[spi_num].tx_count_bytes); - remain = STATES[spi_num].tx_len - STATES[spi_num].tx_cnt; + remain = STATES[spi_num].tx_length_bytes - STATES[spi_num].tx_count_bytes; if (remain) { if (remain >= MXC_SPI_FIFO_DEPTH) { @@ -252,27 +249,32 @@ static void MXC_SPI_RevA2_process(mxc_spi_reva_regs_t *spi) } } - if (STATES[spi_num].tx_cnt == STATES[spi_num].tx_len) { + if (STATES[spi_num].tx_count_bytes == STATES[spi_num].tx_length_bytes) { STATES[spi_num].tx_done = true; } // Unload any SPI data that has come in // Dependent on 1) Valid RX Buffer, 2) RX Length not 0, and 3) RX FIFO Not Empty. - if (STATES[spi_num].rx_buffer && STATES[spi_num].rx_len > 0) { + if (STATES[spi_num].rx_buffer && STATES[spi_num].rx_length_bytes > 0) { // Read the FIFO for byte size transactions (message sizes for 8 bits or less) - if (STATES[spi_num].init.frame_size <= 8) { + if (STATES[spi_num].frame_size <= 8) { while ((spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL)) { - STATES[spi_num].rx_buffer[STATES[spi_num].rx_cnt] = spi->fifo8[0]; - STATES[spi_num].rx_cnt += 1; + // Check for overflow. + if (STATES[spi_num].rx_count_bytes == STATES[spi_num].rx_length_bytes) { + break; + } + + STATES[spi_num].rx_buffer[STATES[spi_num].rx_count_bytes] = spi->fifo8[0]; + STATES[spi_num].rx_count_bytes += 1; } // Read the FIFO for halfword size transactions (message sizes for 9 bits or greater) } else { - STATES[spi_num].rx_cnt += MXC_SPI_RevA2_readRXFIFO16( - spi, &(STATES[spi_num].rx_buffer[STATES[spi_num].rx_cnt]), - STATES[spi_num].rx_len - STATES[spi_num].rx_cnt); + STATES[spi_num].rx_count_bytes += MXC_SPI_RevA2_readRXFIFO16( + spi, &(STATES[spi_num].rx_buffer[STATES[spi_num].rx_count_bytes]), + STATES[spi_num].rx_length_bytes - STATES[spi_num].rx_count_bytes); - remain = STATES[spi_num].rx_len - STATES[spi_num].rx_cnt; + remain = STATES[spi_num].rx_length_bytes - STATES[spi_num].rx_count_bytes; if (remain) { if (remain >= MXC_SPI_FIFO_DEPTH) { @@ -286,38 +288,59 @@ static void MXC_SPI_RevA2_process(mxc_spi_reva_regs_t *spi) } } - if (STATES[spi_num].rx_cnt == STATES[spi_num].rx_len) { + if (STATES[spi_num].rx_count_bytes == STATES[spi_num].rx_length_bytes) { STATES[spi_num].rx_done = true; } + + // Handle Target Transaction Completion. + // Unlike the Controller, there is no Target Done interrupt to handle the callback and set the + // transaction_done flag. + if (STATES[spi_num].controller_target == MXC_SPI_TYPE_TARGET) { + // Check if the transaction is complete. + if (STATES[spi_num].tx_done == true && STATES[spi_num].rx_done == true) { + // Callback if valid. + // Note: If Target Select (TS) Control Scheme is set in SW_App mode, then the caller needs to ensure the + // Target Select (TS) pin is asserted or deasserted in their application. + if (STATES[spi_num].callback) { + STATES[spi_num].callback(STATES[spi_num].callback_data, E_NO_ERROR); + } + + // Target is done after callback (if valid) is handled. + STATES[spi_num].transaction_done = true; + + // Reset the SPI to complete the on-going transaction. + // SPIn may remain busy (SPI_STAT) even after the target select input + // is deasserted. This ensures the SPI block is not busy after a + // target transaction is completed. + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); + spi->ctrl0 |= (MXC_F_SPI_REVA_CTRL0_EN); + } + } } /** Private Function: resetStateStruct * This functions resets the STATE of an SPI instance. * * @param spi_num Index number of SPI instance. - * - * @return Success/Fail, see \ref MXC_Error_Codes for a list of return codes. */ -static int MXC_SPI_RevA2_resetStateStruct(int spi_num) +static void MXC_SPI_RevA2_resetStateStruct(int8_t spi_num) { - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - // Init Data - STATES[spi_num].initialized = false; STATES[spi_num].dma_initialized = false; - STATES[spi_num].init = (const mxc_spi_init_t){ 0 }; + STATES[spi_num].controller_target = MXC_SPI_TYPE_CONTROLLER; + STATES[spi_num].frame_size = 8; // 1 byte frame sizes. + STATES[spi_num].if_mode = MXC_SPI_INTERFACE_STANDARD; // Transaction Members STATES[spi_num].tx_buffer = NULL; - STATES[spi_num].tx_len = 0; - STATES[spi_num].tx_cnt = 0; + STATES[spi_num].tx_length_bytes = 0; + STATES[spi_num].tx_count_bytes = 0; STATES[spi_num].rx_buffer = NULL; - STATES[spi_num].rx_len = 0; - STATES[spi_num].rx_cnt = 0; + STATES[spi_num].rx_length_bytes = 0; + STATES[spi_num].rx_count_bytes = 0; STATES[spi_num].deassert = true; // Default state is TS will be deasserted at the end of a transmission. + STATES[spi_num].ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // Default (0) state. // DMA STATES[spi_num].dma = NULL; @@ -325,247 +348,139 @@ static int MXC_SPI_RevA2_resetStateStruct(int spi_num) STATES[spi_num].rx_dma_ch = -1; // Status Members - STATES[spi_num].controller_done = false; + STATES[spi_num].transaction_done = false; STATES[spi_num].tx_done = false; STATES[spi_num].rx_done = false; - STATES[spi_num].target_done = false; - - return E_NO_ERROR; } /* **** Public Functions **** */ -int MXC_SPI_RevA2_Init(mxc_spi_init_t *init) +int MXC_SPI_RevA2_Init(mxc_spi_reva_regs_t *spi, mxc_spi_type_t controller_target, + mxc_spi_interface_t if_mode, uint32_t freq, uint8_t ts_active_pol_mask) { - int error, spi_num, i; - int tx_ch, rx_ch; - mxc_spi_target_t *target; - mxc_gpio_regs_t *target_port; - - if (init == NULL) { - return E_NULL_PTR; - } + int error; + int8_t spi_num; - // Ensure valid SPI instance. - spi_num = MXC_SPI_GET_IDX(init->spi); + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { return E_BAD_PARAM; } - // For code readability. - target = &(init->target); - if (target == NULL) { - return E_NULL_PTR; - } - // Reset STATE of current SPI instance. - error = MXC_SPI_RevA2_resetStateStruct(spi_num); - if (error != E_NO_ERROR) { - return error; - } - - // Save init data for transactions and handlers. - STATES[spi_num].init = *init; - STATES[spi_num].dma = NULL; - STATES[spi_num].current_target = *target; - - // Set up Target Select Control Scheme. - // Hardware (Automatic) Controlled. - if (init->ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { - // Set up preconfigured TSn Pins. - // Use target.init_mask for most the convenience. - if (init->target.init_mask) { - // Get total number of TSn instances for this SPI instance - for (i = 0; i < MXC_SPI_GET_TOTAL_TS(init->spi); i++) { - // Note: The [] represents the bit location of init_mask - // init_mask[0] <= Target Select 0 (TS0) - // init_mask[1] <= Target Select 1 (TS1) - // init_mask[n] <= Target Select n (TSn) - if (init->target.init_mask & (1 << i)) { - error = MXC_SPI_ConfigTargetSelect(init->spi, i, init->vssel); - if (error != E_NO_ERROR) { - return error; - } - } - } - - MXC_SETFIELD((init->spi)->ctrl0, MXC_F_SPI_REVA_CTRL0_SS_ACTIVE, - ((uint32_t)(init->target.init_mask) - << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS)); - - // If target.init_mask was not used, then read the target settings and initalize the selected index. - // Mainly used to test new HW TSn pins that aren't defined in the parts' mxc_pins.h and pins_{part}.c. - } else { - if (target->index >= MXC_SPI_GET_TOTAL_TS(init->spi)) { - return E_BAD_PARAM; - } - - error = MXC_SPI_ConfigTargetSelect(init->spi, target->index, init->vssel); - if (error != E_NO_ERROR) { - return error; - } - - (init->spi)->ctrl0 |= ((1 << target->index) << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS); + MXC_SPI_RevA2_resetStateStruct(spi_num); - // Set TS Polarity (Default - active low (0)) - if (target->active_polarity) { - (init->spi)->ctrl2 |= ((1 << target->index) << MXC_F_SPI_REVA_CTRL2_SS_POL_POS); - } else { - (init->spi)->ctrl2 &= ~((1 << target->index) << MXC_F_SPI_REVA_CTRL2_SS_POL_POS); - } - } - - // Software Driver Controlled. - } else if (init->ts_control == MXC_SPI_TSCONTROL_SW_DRV) { - // Readbility for register access - target_port = target->pins.port; + // Save init data states. + STATES[spi_num].controller_target = controller_target; + STATES[spi_num].frame_size = 8; + STATES[spi_num].if_mode = if_mode; - // If SPI driver is handling target, make sure the pin function is set as an output (AF: IO). - if ((target->pins.port != NULL) && (target->pins.func == MXC_GPIO_FUNC_OUT)) { - error = MXC_GPIO_Config(&(target->pins)); - if (error != E_NO_ERROR) { - return error; - } - - // Ensure VDDIO/VDDIOH Selection - error = MXC_GPIO_SetVSSEL(target->pins.port, init->vssel, target->pins.mask); - if (error != E_NO_ERROR) { - return error; - } + // Enable SPI port. + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); + spi->ctrl0 |= (MXC_F_SPI_REVA_CTRL0_EN); - // Set IDLE TS Polarity (Default - active low (0)) - if (target->active_polarity) { - // Active HIGH (1), Set TS Idle State to LOW (0) - target_port->out_clr |= target->pins.mask; - } else { - // Active LOW (0), Set TS Idle State to HIGH (1) - target_port->out_set |= target->pins.mask; - } + // Set Controller (L. Master) or Target (L. Slave) mode. + switch (controller_target) { + case MXC_SPI_TYPE_CONTROLLER: + spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_MST_MODE; + break; - } else { - return E_BAD_PARAM; - } + case MXC_SPI_TYPE_TARGET: + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_MST_MODE); + break; - // Don't do anything if SW Application is handling Target Select (TS) pin - // while still checking for proper ts_control parameter. - // Software Application Controlled. - } else if (init->ts_control != MXC_SPI_TSCONTROL_SW_APP) { - // Not a valid Target Select (TS) Control option. + default: return E_BAD_PARAM; } - // Enable SPI port. - (init->spi)->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); - (init->spi)->ctrl0 |= (MXC_F_SPI_REVA_CTRL0_EN); - - // Select Controller (L. Master) or Target (L. Slave) Mode. - if (init->type == MXC_SPI_TYPE_CONTROLLER) { - (init->spi)->ctrl0 |= MXC_F_SPI_REVA_CTRL0_MST_MODE; - } else { - (init->spi)->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_MST_MODE; - } - - // Set frame size. - if (init->frame_size <= 1 || init->frame_size > 16) { - return E_BAD_PARAM; - } else { - (init->spi)->ctrl2 |= (init->frame_size) << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS; - } + // Set default frame size to 8 bits wide. + MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, 8 << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); // Remove any delay between TS (L. SS) and SCLK edges. - (init->spi)->sstime = (1 << MXC_F_SPI_REVA_SSTIME_PRE_POS) | - (1 << MXC_F_SPI_REVA_SSTIME_POST_POS) | - (1 << MXC_F_SPI_REVA_SSTIME_INACT_POS); + spi->sstime = (1 << MXC_F_SPI_REVA_SSTIME_PRE_POS) | (1 << MXC_F_SPI_REVA_SSTIME_POST_POS) | + (1 << MXC_F_SPI_REVA_SSTIME_INACT_POS); // Enable TX/RX FIFOs - (init->spi)->dma |= MXC_F_SPI_REVA_DMA_TX_FIFO_EN | MXC_F_SPI_REVA_DMA_RX_FIFO_EN; + spi->dma |= MXC_F_SPI_REVA_DMA_TX_FIFO_EN | MXC_F_SPI_REVA_DMA_RX_FIFO_EN; // Set TX and RX Threshold to (FIFO_DEPTH - 1) and (0), respectively. - MXC_SETFIELD((init->spi)->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, ((MXC_SPI_FIFO_DEPTH - 1) << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); - MXC_SETFIELD((init->spi)->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, - (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); - // Set Clock Mode (CPOL and CPHA). - error = MXC_SPI_SetClkMode((init->spi), (init->mode)); + // Set Default Clock Mode (CPOL: 0, and CPHA: 0). + error = MXC_SPI_SetClkMode((mxc_spi_regs_t *)spi, MXC_SPI_CLKMODE_0); if (error != E_NO_ERROR) { return error; } // Interface mode: 3-wire, standard (4-wire), dual, quad. - error = MXC_SPI_SetInterface((init->spi), (init->mode)); + error = MXC_SPI_SetInterface((mxc_spi_regs_t *)spi, if_mode); if (error != E_NO_ERROR) { return error; } - error = MXC_SPI_SetFrequency((init->spi), (init->freq)); + error = MXC_SPI_SetFrequency((mxc_spi_regs_t *)spi, freq); if (error != E_NO_ERROR) { return error; } // Clear any interrupt flags that may already be set. - (init->spi)->intfl = (init->spi)->intfl; - (init->spi)->inten = 0; - - if (init->use_dma == false) { - // Enable Controller Done Interrupt. - (init->spi)->inten |= MXC_F_SPI_REVA_INTEN_MST_DONE; - } - - // Set callback. - STATES[spi_num].callback = init->callback; - STATES[spi_num].callback_data = init->callback_data; + spi->intfl = spi->intfl; + spi->inten = 0; - // Setup DMA features if used. - if (init->use_dma) { - // Even though the Init Struct has a pointer to the DMA instance, - // this will make the code a bit more readable since the DMA - // instance is now type casted with the DMA RevA Registers. - STATES[spi_num].dma = (mxc_dma_reva_regs_t *)(init->dma); + // Clear the HW TS settings (These are set in the transaction functions). + MXC_SETFIELD(spi->ctrl0, MXC_F_SPI_REVA_CTRL0_SS_ACTIVE, 0); -#if (MXC_DMA_INSTANCES == 1) - error = MXC_DMA_Init(); -#else - error = MXC_DMA_Init(init->dma); -#endif - if (error != E_NO_ERROR) { - return error; - } + // Set the TS Active Polarity settings. + MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_SS_POL, + ts_active_pol_mask << MXC_F_SPI_REVA_CTRL2_SS_POL_POS); - // Acquire DMA Channels for SPI TX/RX - STATES[spi_num].tx_dma_ch = MXC_DMA_AcquireChannel(); - STATES[spi_num].rx_dma_ch = MXC_DMA_AcquireChannel(); + return E_NO_ERROR; +} - tx_ch = STATES[spi_num].tx_dma_ch; - rx_ch = STATES[spi_num].rx_dma_ch; +int MXC_SPI_RevA2_Config(mxc_spi_cfg_t *cfg) +{ + int error; + int8_t spi_num; - // Check if failed to acquire channel. - if (STATES[spi_num].tx_dma_ch < 0 || STATES[spi_num].rx_dma_ch < 0) { - return E_NONE_AVAIL; - } + if (cfg == NULL) { + return E_NULL_PTR; + } - // TX Channel - STATES[spi_num].dma->ch[tx_ch].ctrl |= - (MXC_F_DMA_REVA_CTRL_CTZ_IE); // | MXC_F_DMA_REVA_CTRL_DIS_IE); - STATES[spi_num].dma->inten |= (1 << tx_ch); + // Ensure valid SPI instance. + spi_num = MXC_SPI_GET_IDX(cfg->spi); + if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { + return E_BAD_PARAM; + } - // RX Channel - STATES[spi_num].dma->ch[rx_ch].ctrl |= - (MXC_F_DMA_REVA_CTRL_CTZ_IE); // | MXC_F_DMA_REVA_CTRL_DIS_IE); - STATES[spi_num].dma->inten |= (1 << rx_ch); + // Set Single Frame Size. + error = MXC_SPI_SetFrameSize((cfg->spi), (cfg->frame_size)); + if (error != E_NO_ERROR) { + return error; + } - STATES[spi_num].dma_initialized = true; + // Set Clock Mode (CPOL and CPHA). + error = MXC_SPI_SetClkMode((cfg->spi), (cfg->clk_mode)); + if (error != E_NO_ERROR) { + return error; } - // If successful, mark STATE of this SPI instance as initialized. - STATES[spi_num].initialized = true; + // Setup DMA features if used. + if (cfg->use_dma_tx || cfg->use_dma_rx) { + error = MXC_SPI_RevA2_DMA_Init((mxc_spi_reva_regs_t *)(cfg->spi), + (mxc_dma_reva_regs_t *)(cfg->dma), (cfg->use_dma_tx), + (cfg->use_dma_rx)); + if (error != E_NO_ERROR) { + return error; + } + } return E_NO_ERROR; } int MXC_SPI_RevA2_Shutdown(mxc_spi_reva_regs_t *spi) { - int spi_num, error; + int8_t spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { @@ -596,61 +511,73 @@ int MXC_SPI_RevA2_Shutdown(mxc_spi_reva_regs_t *spi) STATES[spi_num].rx_dma_ch = E_NO_DEVICE; } - if (STATES[spi_num].init.use_dma) { + if (STATES[spi_num].dma_initialized) { MXC_DMA_DeInit(); } // Reset the SPI instance's STATE when shutting down. - error = MXC_SPI_RevA2_resetStateStruct(spi_num); - if (error != E_NO_ERROR) { - return error; - } + MXC_SPI_RevA2_resetStateStruct(spi_num); return E_NO_ERROR; } uint32_t MXC_SPI_RevA2_GetFlags(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - - MXC_ASSERT(spi_num >= 0); - return spi->intfl; } void MXC_SPI_RevA2_ClearFlags(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - - MXC_ASSERT(spi_num >= 0); - spi->intfl = spi->intfl; } void MXC_SPI_RevA2_EnableInt(mxc_spi_reva_regs_t *spi, uint32_t en) { - int spi_num; + spi->inten |= en; +} + +void MXC_SPI_RevA2_DisableInt(mxc_spi_reva_regs_t *spi, uint32_t dis) +{ + spi->inten &= ~(dis); +} + +int MXC_SPI_RevA2_SetTSControl(mxc_spi_reva_regs_t *spi, mxc_spi_tscontrol_t ts_control) +{ + int8_t spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); + if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { + return E_BAD_PARAM; + } - MXC_ASSERT(spi_num >= 0); + switch (ts_control) { + case MXC_SPI_TSCONTROL_HW_AUTO: + break; - spi->inten |= en; + case MXC_SPI_TSCONTROL_SW_APP: + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_SS_ACTIVE); + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL2_SS_POL); + break; + + default: + return E_BAD_PARAM; + } + + STATES[spi_num].ts_control = ts_control; + + return E_NO_ERROR; } -void MXC_SPI_RevA2_DisableInt(mxc_spi_reva_regs_t *spi, uint32_t dis) +mxc_spi_tscontrol_t MXC_SPI_RevA2_GetTSControl(mxc_spi_reva_regs_t *spi) { - int spi_num; + int8_t spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); + if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { + return E_BAD_PARAM; + } - MXC_ASSERT(spi_num >= 0); - - spi->inten &= ~(dis); + return (STATES[spi_num].ts_control); } int MXC_SPI_RevA2_SetFrequency(mxc_spi_reva_regs_t *spi, uint32_t freq) @@ -698,10 +625,6 @@ int MXC_SPI_RevA2_SetFrequency(mxc_spi_reva_regs_t *spi, uint32_t freq) int MXC_SPI_RevA2_GetFrequency(mxc_spi_reva_regs_t *spi) { - if (MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi) < 0) { - return E_BAD_PARAM; - } - unsigned scale, lo_clk, hi_clk; scale = (spi->clkctrl & MXC_F_SPI_REVA_CLKCTRL_CLKDIV) >> MXC_F_SPI_REVA_CLKCTRL_CLKDIV_POS; @@ -713,7 +636,7 @@ int MXC_SPI_RevA2_GetFrequency(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_SetFrameSize(mxc_spi_reva_regs_t *spi, int frame_size) { - int spi_num; + int8_t spi_num; int saved_enable_state; // HW has problem with these two character sizes @@ -722,49 +645,40 @@ int MXC_SPI_RevA2_SetFrameSize(mxc_spi_reva_regs_t *spi, int frame_size) } spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; + + if ((spi->stat & MXC_F_SPI_REVA_STAT_BUSY) && + (STATES[spi_num].controller_target == MXC_SPI_TYPE_CONTROLLER)) { + return E_BAD_STATE; } // Set up the character size. - if (!(spi->stat & MXC_F_SPI_REVA_STAT_BUSY)) { - saved_enable_state = spi->ctrl0 | MXC_F_SPI_REVA_CTRL0_EN; - - // If enabled, disable SPI before changing character size. - if (saved_enable_state) { - spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); - } + saved_enable_state = spi->ctrl0 | MXC_F_SPI_REVA_CTRL0_EN; - // Update data size from save Init function. - STATES[spi_num].init.frame_size = frame_size; + // If enabled, disable SPI before changing character size. + if (saved_enable_state) { + spi->ctrl0 &= ~(MXC_F_SPI_REVA_CTRL0_EN); + } - if (frame_size < 16) { - MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, - frame_size << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); - } else { - // Set to 16 bits per character as default. - MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, - 0 << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); - } + // Update data size from save Init function. + STATES[spi_num].frame_size = frame_size; - // Return back to original SPI enable state. - MXC_SETFIELD(spi->ctrl0, MXC_F_SPI_REVA_CTRL0_EN, saved_enable_state); + if (frame_size < 16) { + MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, + frame_size << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); } else { - return E_BAD_STATE; + // Set to 16 bits per character as default. + MXC_SETFIELD(spi->ctrl2, MXC_F_SPI_REVA_CTRL2_NUMBITS, + 0 << MXC_F_SPI_REVA_CTRL2_NUMBITS_POS); } + // Return back to original SPI enable state. + MXC_SETFIELD(spi->ctrl0, MXC_F_SPI_REVA_CTRL0_EN, saved_enable_state); + return E_NO_ERROR; } int MXC_SPI_RevA2_GetFrameSize(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - // NUMBITS = 0 means 16-bits per character if (!(spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_NUMBITS)) { return 16; @@ -773,19 +687,12 @@ int MXC_SPI_RevA2_GetFrameSize(mxc_spi_reva_regs_t *spi) } } -int MXC_SPI_RevA2_SetInterface(mxc_spi_reva_regs_t *spi, mxc_spi_interface_t mode) +int MXC_SPI_RevA2_SetInterface(mxc_spi_reva_regs_t *spi, mxc_spi_interface_t if_mode) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - // Clear before setting spi->ctrl2 &= ~(MXC_F_SPI_REVA_CTRL2_THREE_WIRE | MXC_F_SPI_REVA_CTRL2_DATA_WIDTH); - switch (mode) { + switch (if_mode) { case MXC_SPI_INTERFACE_3WIRE: spi->ctrl2 |= MXC_F_SPI_REVA_CTRL2_THREE_WIRE; break; @@ -809,7 +716,7 @@ int MXC_SPI_RevA2_SetInterface(mxc_spi_reva_regs_t *spi, mxc_spi_interface_t mod } // Save state of new mode - STATES[spi_num].init.mode = mode; + STATES[MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi)].if_mode = if_mode; return E_NO_ERROR; } @@ -833,13 +740,6 @@ mxc_spi_interface_t MXC_SPI_RevA2_GetInterface(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_SetClkMode(mxc_spi_reva_regs_t *spi, mxc_spi_clkmode_t clk_mode) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - switch (clk_mode) { // CPOL: 0 CPHA: 0 case MXC_SPI_CLKMODE_0: @@ -872,21 +772,11 @@ int MXC_SPI_RevA2_SetClkMode(mxc_spi_reva_regs_t *spi, mxc_spi_clkmode_t clk_mod break; } - // Save state of new clock mode. - STATES[spi_num].init.clk_mode = clk_mode; - return E_NO_ERROR; } mxc_spi_clkmode_t MXC_SPI_RevA2_GetClkMode(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - if (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_CLKPHA) { if (spi->ctrl2 & MXC_F_SPI_REVA_CTRL2_CLKPOL) { return MXC_SPI_CLKMODE_3; @@ -904,16 +794,9 @@ mxc_spi_clkmode_t MXC_SPI_RevA2_GetClkMode(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_SetCallback(mxc_spi_reva_regs_t *spi, mxc_spi_callback_t callback, void *data) { - int spi_num; + int8_t spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - if (STATES[spi_num].initialized == false) { - return E_BAD_STATE; - } STATES[spi_num].callback = callback; STATES[spi_num].callback_data = data; @@ -921,39 +804,6 @@ int MXC_SPI_RevA2_SetCallback(mxc_spi_reva_regs_t *spi, mxc_spi_callback_t callb return E_NO_ERROR; } -int MXC_SPI_RevA2_SetInitStruct(mxc_spi_reva_regs_t *spi, mxc_spi_init_t *init) -{ - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - // Make sure SPI instance is initialized - if (STATES[spi_num].initialized != true) { - return E_BAD_STATE; - } - - STATES[spi_num].init = *init; - STATES[spi_num].dma = (mxc_dma_reva_regs_t *)(init->dma); - - return E_NO_ERROR; -} - -mxc_spi_init_t MXC_SPI_RevA2_GetInitStruct(mxc_spi_reva_regs_t *spi) -{ - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); - - // Make sure SPI instance is initialized - MXC_ASSERT(STATES[spi_num].initialized == true); - - return (STATES[spi_num].init); -} - int MXC_SPI_RevA2_GetActive(mxc_spi_reva_regs_t *spi) { if (spi->stat & MXC_F_SPI_REVA_STAT_BUSY) { @@ -965,13 +815,6 @@ int MXC_SPI_RevA2_GetActive(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_ReadyForSleep(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - if (spi->stat & MXC_F_SPI_REVA_STAT_BUSY || (spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) || (spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL)) { return E_BUSY; @@ -982,27 +825,13 @@ int MXC_SPI_RevA2_ReadyForSleep(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_SetDummyTX(mxc_spi_reva_regs_t *spi, uint16_t tx_value) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - STATES[spi_num].tx_dummy_value = tx_value; + STATES[MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi)].tx_dummy_value = tx_value; return E_NO_ERROR; } int MXC_SPI_RevA2_StartTransmission(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - if (MXC_SPI_GetActive((mxc_spi_regs_t *)spi) == E_BUSY) { return E_BUSY; } @@ -1014,12 +843,9 @@ int MXC_SPI_RevA2_StartTransmission(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_AbortTransmission(mxc_spi_reva_regs_t *spi) { - int spi_num; + int8_t spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } // Disable interrupts, clear the flags. spi->inten = 0; @@ -1039,35 +865,19 @@ int MXC_SPI_RevA2_AbortTransmission(mxc_spi_reva_regs_t *spi) uint8_t MXC_SPI_RevA2_GetTXFIFOAvailable(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); - return MXC_SPI_FIFO_DEPTH - ((spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) >> MXC_F_SPI_REVA_DMA_TX_LVL_POS); } uint8_t MXC_SPI_RevA2_GetRXFIFOAvailable(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); - return (spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL) >> MXC_F_SPI_REVA_DMA_RX_LVL_POS; } int MXC_SPI_RevA2_ClearTXFIFO(mxc_spi_reva_regs_t *spi) { - int spi_num; uint32_t save_state; - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - save_state = (spi->dma & (MXC_F_SPI_REVA_DMA_TX_FIFO_EN | MXC_F_SPI_REVA_DMA_DMA_TX_EN)); // Disable FIFOs before clearing as recommended by UG. @@ -1083,14 +893,8 @@ int MXC_SPI_RevA2_ClearTXFIFO(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_ClearRXFIFO(mxc_spi_reva_regs_t *spi) { - int spi_num; uint32_t save_state; - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - save_state = (spi->dma & (MXC_F_SPI_REVA_DMA_RX_FIFO_EN | MXC_F_SPI_REVA_DMA_DMA_RX_EN)); // Disable FIFOs before clearing as recommended by UG. @@ -1106,13 +910,6 @@ int MXC_SPI_RevA2_ClearRXFIFO(mxc_spi_reva_regs_t *spi) int MXC_SPI_RevA2_SetTXThreshold(mxc_spi_reva_regs_t *spi, uint8_t thd_val) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - // Valid values for the threshold are 0x1 to 0x1F if (thd_val > (MXC_SPI_FIFO_DEPTH - 1) || thd_val == 0) { return E_BAD_PARAM; @@ -1126,13 +923,6 @@ int MXC_SPI_RevA2_SetTXThreshold(mxc_spi_reva_regs_t *spi, uint8_t thd_val) int MXC_SPI_RevA2_SetRXThreshold(mxc_spi_reva_regs_t *spi, uint8_t thd_val) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - if (thd_val >= (MXC_SPI_FIFO_DEPTH - 1)) { return E_BAD_PARAM; } @@ -1145,83 +935,78 @@ int MXC_SPI_RevA2_SetRXThreshold(mxc_spi_reva_regs_t *spi, uint8_t thd_val) uint8_t MXC_SPI_RevA2_GetTXThreshold(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); - return (spi->dma & MXC_F_SPI_REVA_DMA_TX_THD_VAL) >> MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS; } uint8_t MXC_SPI_RevA2_GetRXThreshold(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); - return (spi->dma & MXC_F_SPI_REVA_DMA_RX_THD_VAL) >> MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS; } /* ** DMA-Specific Functions ** */ // Available for switching between DMA and non-DMA transactions -int MXC_SPI_RevA2_DMA_Init(mxc_spi_init_t *init) +int MXC_SPI_RevA2_DMA_Init(mxc_spi_reva_regs_t *spi, mxc_dma_reva_regs_t *dma, bool use_dma_tx, + bool use_dma_rx) { - int error, spi_num; - int tx_ch, rx_ch; + int error; + int tx_ch, rx_ch; // For readability. + int8_t spi_num; - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)(init->spi)); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (init == NULL) { + if (dma == NULL) { return E_NULL_PTR; } - if (init->dma == NULL || init->use_dma == false) { - return E_BAD_PARAM; - } - - // Exit function is DMA already initialized. - if (MXC_SPI_RevA2_DMA_GetInitialized((mxc_spi_reva_regs_t *)(init->spi))) { + if (STATES[spi_num].dma_initialized) { + // Exit function if DMA is already initialized. return E_NO_ERROR; } - // Even though the Init Struct has a pointer to the DMA instance, - // this will make the code a bit more readable since the DMA - // instance is now type casted with the DMA RevA Registers. - STATES[spi_num].dma = (mxc_dma_reva_regs_t *)(init->dma); + STATES[spi_num].dma = dma; #if (MXC_DMA_INSTANCES == 1) error = MXC_DMA_Init(); #else - error = MXC_DMA_Init(init->dma); + error = MXC_DMA_Init(dma); #endif if (error != E_NO_ERROR) { return error; } - // Acquire DMA Channels for SPI TX/RX - STATES[spi_num].tx_dma_ch = MXC_DMA_AcquireChannel(); - STATES[spi_num].rx_dma_ch = MXC_DMA_AcquireChannel(); + // Set up SPI DMA TX. + if (use_dma_tx) { + STATES[spi_num].tx_dma_ch = MXC_DMA_AcquireChannel(); + tx_ch = STATES[spi_num].tx_dma_ch; - tx_ch = STATES[spi_num].tx_dma_ch; - rx_ch = STATES[spi_num].rx_dma_ch; + if (STATES[spi_num].tx_dma_ch < 0) { + return E_NONE_AVAIL; + } - // Check if failed to acquire channel. - if (STATES[spi_num].tx_dma_ch < 0 || STATES[spi_num].rx_dma_ch < 0) { - return E_NONE_AVAIL; + // TX Channel + STATES[spi_num].dma->ch[tx_ch].ctrl |= (MXC_F_DMA_REVA_CTRL_CTZ_IE); + STATES[spi_num].dma->inten |= (1 << tx_ch); } - // TX Channel - STATES[spi_num].dma->ch[tx_ch].ctrl |= (MXC_F_DMA_REVA_CTRL_CTZ_IE); - STATES[spi_num].dma->inten |= (1 << tx_ch); + // Set up SPI DMA RX. + if (use_dma_rx) { + STATES[spi_num].rx_dma_ch = MXC_DMA_AcquireChannel(); + rx_ch = STATES[spi_num].rx_dma_ch; + + if (STATES[spi_num].rx_dma_ch < 0) { + return E_NONE_AVAIL; + } - // RX Channel - STATES[spi_num].dma->ch[rx_ch].ctrl |= (MXC_F_DMA_REVA_CTRL_CTZ_IE); - STATES[spi_num].dma->inten |= (1 << rx_ch); + // RX Channel + STATES[spi_num].dma->ch[rx_ch].ctrl |= (MXC_F_DMA_REVA_CTRL_CTZ_IE); + STATES[spi_num].dma->inten |= (1 << rx_ch); + } + + error = MXC_SPI_DMA_SetRequestSelect((mxc_spi_regs_t *)spi, use_dma_tx, use_dma_rx); + if (error != E_NO_ERROR) { + return error; + } STATES[spi_num].dma_initialized = true; @@ -1232,51 +1017,27 @@ int MXC_SPI_RevA2_DMA_Init(mxc_spi_init_t *init) // Useful for switching from non-DMA to DMA transactions. bool MXC_SPI_RevA2_DMA_GetInitialized(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - return (STATES[spi_num].dma_initialized); + return (STATES[MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi)].dma_initialized); } int MXC_SPI_RevA2_DMA_GetTXChannel(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - return (STATES[spi_num].tx_dma_ch); + return (STATES[MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi)].tx_dma_ch); } int MXC_SPI_RevA2_DMA_GetRXChannel(mxc_spi_reva_regs_t *spi) { - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - return (STATES[spi_num].rx_dma_ch); + return (STATES[MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi)].rx_dma_ch); } int MXC_SPI_RevA2_DMA_SetRequestSelect(mxc_spi_reva_regs_t *spi, uint32_t tx_reqsel, uint32_t rx_reqsel) { - int spi_num; + int8_t spi_num; uint32_t tx_ch; uint32_t rx_ch; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } // Ensure DMA was configured before setting DMA Request Selects. if (STATES[spi_num].dma == NULL) { @@ -1303,102 +1064,81 @@ int MXC_SPI_RevA2_DMA_SetRequestSelect(mxc_spi_reva_regs_t *spi, uint32_t tx_req // LSB and MSB. // Example: TX: 0x1234 => RX: 0x3412 // Note: Use __REV assembly instruction for quicker Swap implementation. -void MXC_SPI_RevA2_DMA_SwapByte(uint8_t *buffer, uint32_t len_bytes) +void MXC_SPI_RevA2_DMA_SwapByte(uint8_t *buffer, uint32_t length_bytes) { int i; MXC_ASSERT(buffer != NULL); - for (i = 0; i < len_bytes; i += 2) { + for (i = 0; i < length_bytes; i += 2) { uint8_t temp = buffer[i]; buffer[i] = buffer[i + 1]; buffer[i + 1] = temp; } } -/* ** Transaction Functions ** */ +/* ** Transaction Helper Functions ** */ -int MXC_SPI_RevA2_ControllerTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, - uint8_t deassert, mxc_spi_target_t *target) +// SPI DMA/non-DMA Transaction Setup Helper Function. +static void MXC_SPI_RevA2_transactionSetup(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, bool use_dma) { - int spi_num, tx_dummy_fr_len; + int tx_dummy_length_frames; + int8_t spi_num; + // For readability purposes. + int rx_ch, tx_ch; // Ensure valid SPI Instance. spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - // Ensure valid chip select option. - if (target == NULL) { - return E_NULL_PTR; - } - - // Make sure SPI Instance was initialized. - if (STATES[spi_num].initialized == false) { - return E_BAD_STATE; - } - - // Make sure DMA is not initialized. - if (STATES[spi_num].init.use_dma == true) { - return E_BAD_STATE; - } // Initialize SPIn state to handle data. - STATES[spi_num].controller_done = false; + STATES[spi_num].transaction_done = false; STATES[spi_num].tx_buffer = tx_buffer; - STATES[spi_num].tx_cnt = 0; + STATES[spi_num].tx_count_bytes = 0; STATES[spi_num].tx_done = false; STATES[spi_num].rx_buffer = rx_buffer; - STATES[spi_num].rx_cnt = 0; + STATES[spi_num].rx_count_bytes = 0; STATES[spi_num].rx_done = false; // Max number of frames to transmit/receive. - if (tx_fr_len > (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)) { - return E_OVERFLOW; - } - - if (rx_fr_len > (MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS)) { - return E_OVERFLOW; - } + MXC_ASSERT(tx_length_frames < + (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)); + MXC_ASSERT(rx_length_frames < + (MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS)); // STATES[n] TX/RX Length Fields are in terms of number of bytes to send/receive. - if (STATES[spi_num].init.frame_size <= 8) { - STATES[spi_num].tx_len = tx_fr_len; - STATES[spi_num].rx_len = rx_fr_len; + if (STATES[spi_num].frame_size <= 8) { + STATES[spi_num].tx_length_bytes = tx_length_frames; + STATES[spi_num].rx_length_bytes = rx_length_frames; } else { - STATES[spi_num].tx_len = tx_fr_len * 2; - STATES[spi_num].rx_len = rx_fr_len * 2; + STATES[spi_num].tx_length_bytes = tx_length_frames * 2; + STATES[spi_num].rx_length_bytes = rx_length_frames * 2; } - STATES[spi_num].deassert = deassert; - STATES[spi_num].current_target = *target; - // Set the number of messages to transmit/receive for the SPI transaction. - if (STATES[spi_num].init.mode == MXC_SPI_INTERFACE_STANDARD) { - if (rx_fr_len > tx_fr_len) { + if (STATES[spi_num].if_mode == MXC_SPI_INTERFACE_STANDARD) { + if (rx_length_frames > tx_length_frames) { // 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. - tx_dummy_fr_len = rx_fr_len - tx_fr_len; + tx_dummy_length_frames = rx_length_frames - tx_length_frames; // Check whether new frame length exceeds the possible number of frames to transmit. - if ((tx_fr_len + tx_dummy_fr_len) > - (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)) { - return E_OVERFLOW; - } + MXC_ASSERT((tx_length_frames + tx_dummy_length_frames) < + (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)); - spi->ctrl1 = ((tx_fr_len + tx_dummy_fr_len) << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); + spi->ctrl1 = ((tx_length_frames + tx_dummy_length_frames) + << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); } else { - spi->ctrl1 = (tx_fr_len << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); + spi->ctrl1 = (tx_length_frames << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); } } else { // mode != MXC_SPI_INTERFACE_STANDARD - spi->ctrl1 = (tx_fr_len << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS) | - (rx_fr_len << MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS); + spi->ctrl1 = (tx_length_frames << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS) | + (rx_length_frames << MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS); } // Disable FIFOs before clearing as recommended by UG. @@ -1406,33 +1146,207 @@ int MXC_SPI_RevA2_ControllerTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_bu MXC_F_SPI_REVA_DMA_RX_FIFO_EN | MXC_F_SPI_REVA_DMA_DMA_RX_EN); spi->dma |= (MXC_F_SPI_REVA_DMA_TX_FLUSH | MXC_F_SPI_REVA_DMA_RX_FLUSH); - if (tx_fr_len > 0) { - // Enable TX FIFO & TX Threshold crossed interrupt. + //>>> Start of SPI DMA transaction setup. + if (use_dma) { + // Enable TX FIFO before configuring. spi->dma |= (MXC_F_SPI_REVA_DMA_TX_FIFO_EN); - spi->inten |= MXC_F_SPI_REVA_INTEN_TX_THD; - // Set TX Threshold to minimum value after re-enabling TX FIFO. + // Set TX and RX Thresholds before loading FIFO. MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, - (1 << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); - } - - if (rx_fr_len > 0) { - // Enable RX FIFO & RX Threshold crossed interrupt. - spi->dma |= (MXC_F_SPI_REVA_DMA_RX_FIFO_EN); - spi->inten |= MXC_F_SPI_REVA_INTEN_RX_THD; - - // Set RX Threshold to minimum value after re-enabling RX FIFO. + ((MXC_SPI_FIFO_DEPTH - 1) << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); - } - // This private function, MXC_SPI_RevA2_process, call fills the TX FIFO as much as possible - // before launching the transaction. Subsequent FIFO management will - // be handled from the MXC_SPI_Handler which should be called in SPI_IRQHandler. - MXC_SPI_RevA2_process(spi); + // Set up DMA TX Transactions. + // Note: Number of transmitting frames greatly depends on the SPI DMA register settings for + // the DMA burst size and TX Threshold values. + // 1) For TX transmissions. + if (tx_length_frames > 1) { + // For readability purposes. + tx_ch = STATES[spi_num].tx_dma_ch; + + // Configure DMA TX depending on frame width. + // 2-8 bit wide frames. + if (STATES[spi_num].frame_size <= 8) { + // Hardware requires writing the first byte into the FIFO manually. + spi->fifo8[0] = tx_buffer[0]; + + // Threshold set to 2 frames (2 bytes) after pre-loading first byte for DMA. + // This is the minimum threshold to handle any number of transmitting frames. + // Note: This case is handling TX transactions of greater than 1 frame. + // Threshold of 1 frame does not work. + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, + (2 << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); + + STATES[spi_num].dma->ch[tx_ch].src = (uint32_t)(tx_buffer + 1); // 1 Byte offset + STATES[spi_num].dma->ch[tx_ch].cnt = (tx_length_frames - 1); + + // Set to 3 bytes (3 frames) burst size. + // Due to design: burst_size = threshold + 1 + // Note: Assigning value of 2 to register-field equals 3 bytes transferred in/out of DMA. + // Add 1 to the register-field setting to get the number of bytes for burst. + MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_BURST_SIZE, + (2 << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS)); + + // Set source and destination width to one byte. + MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, + MXC_S_DMA_REVA_CTRL_SRCWD_BYTE); + MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, + MXC_S_DMA_REVA_CTRL_DSTWD_BYTE); + + // 9-16 bit wide frames. + } else { + // Hardware requires writing the first bytes into the FIFO manually. + STATES[spi_num].tx_count_bytes += + MXC_SPI_RevA2_writeTXFIFO16(spi, (uint8_t *)(STATES[spi_num].tx_buffer), 2); + + // Threshold set to 3 frames (6 bytes) after pre-loading FIFO for DMA. + // This is the minimum threshold to handle any number of transmitting frames. + // Note: This case is handling TX transactions of greater than 1 frame. + // Threshold of 1 or 2 frames does not work. + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, + (3 << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); + + STATES[spi_num].dma->ch[tx_ch].src = + (uint32_t)(tx_buffer + STATES[spi_num].tx_count_bytes); + STATES[spi_num].dma->ch[tx_ch].cnt = + (STATES[spi_num].tx_length_bytes - STATES[spi_num].tx_count_bytes); + + // Set to 4 bytes (2 frames) burst size. + // Due to design: burst_size = threshold + 1 + // Note: Assigning value of 3 to register-field equals 4 bytes. + // Add 1 to the register-field setting to get the number of bytes for burst. + MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_BURST_SIZE, + (3 << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS)); + + // Set source and destination width to two bytes. + MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, + MXC_S_DMA_REVA_CTRL_SRCWD_HALFWORD); + MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, + MXC_S_DMA_REVA_CTRL_DSTWD_HALFWORD); + } - // Start the SPI transaction. - spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_START; + STATES[spi_num].dma->ch[tx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_SRCINC; + STATES[spi_num].dma->ch[tx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_EN; // Start the DMA + + // 2) For single character transmissions. + // NOTE: Single-length transmissions does not trigger CTZ. + } else if (tx_length_frames == 1) { + // Write first frame into FIFO. + if (STATES[spi_num].frame_size <= 8) { + spi->fifo8[0] = tx_buffer[0]; + } else { + MXC_SPI_RevA2_writeTXFIFO16(spi, (uint8_t *)(STATES[spi_num].tx_buffer), 2); + } + + // If there is no RX DMA and only one frame is transmitted, then + // the transaction is done. Single-length transmissions + // does not trigger a CTZ interrupt. + if (rx_length_frames > 0 && rx_buffer != NULL) { + STATES[spi_num].transaction_done = true; + } + + STATES[spi_num].tx_done = true; + + // 3) Set up DMA TX for RX only transactions. + // Note: Even if you are not transmitting anything in standard 4-wire mode, + // the hardware always assume full duplex. Therefore dummy bytes + // must be transmitted to support half duplex. The number of bytes to transmit + // AND receive is set by TX_NUM_CHAR, and the RX_NUM_CHAR field of ctrl1 is ignored. + } else if (tx_length_frames == 0 && STATES[spi_num].if_mode == MXC_SPI_INTERFACE_STANDARD) { + // For readability purposes. + tx_ch = STATES[spi_num].tx_dma_ch; + + // Configure TX DMA channel to retransmit the dummy byte. + STATES[spi_num].dma->ch[tx_ch].src = (uint32_t)(&(STATES[spi_num].tx_dummy_value)); + STATES[spi_num].dma->ch[tx_ch].cnt = STATES[spi_num].rx_length_bytes; // Only receiving + STATES[spi_num].dma->ch[tx_ch].ctrl &= ~MXC_F_DMA_REVA_CTRL_SRCINC; + STATES[spi_num].dma->ch[tx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_EN; // Start the DMA + } + + // Enable SPI TX DMA after configuring. + spi->dma |= (MXC_F_SPI_REVA_DMA_DMA_TX_EN); + + // Set up DMA RX Transactions. + if (rx_length_frames > 0 && rx_buffer != NULL) { + // For readability purposes. + rx_ch = STATES[spi_num].rx_dma_ch; + + // Enable RX DMA channel before configuring. + spi->dma |= (MXC_F_SPI_REVA_DMA_RX_FIFO_EN); + + // Set RX threshold to minimum value to handle any number of received frames. + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, + (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); + + STATES[spi_num].dma->ch[rx_ch].dst = (uint32_t)rx_buffer; + STATES[spi_num].dma->ch[rx_ch].cnt = STATES[spi_num].rx_length_bytes; + + // Set to one byte burst size - minimum value to handle any number of recevied frames. + MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_BURST_SIZE, + (0 << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS)); + + // Match frame size (in terms of bytes) in DMA ctrl settings. + if (STATES[spi_num].frame_size <= 8) { + // Set source and destination width to one byte + MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, + MXC_S_DMA_REVA_CTRL_SRCWD_BYTE); + MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, + MXC_S_DMA_REVA_CTRL_DSTWD_BYTE); + } else { + // Set source destination width to 2 bytes + MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, + MXC_S_DMA_REVA_CTRL_SRCWD_HALFWORD); + MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, + MXC_S_DMA_REVA_CTRL_DSTWD_HALFWORD); + } + + STATES[spi_num].dma->ch[rx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_DSTINC; + STATES[spi_num].dma->ch[rx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_EN; // Start the DMA + + // Enable SPI RX DMA after configuring. + spi->dma |= (MXC_F_SPI_REVA_DMA_DMA_RX_EN); + } + //<<< End of SPI DMA transaction setup. + //>>> Start of SPI non-DMA transaction setup. + } else { + // Finish setting up SPI for TX and RX. + if (tx_length_frames > 0) { + // Enable TX FIFO & TX Threshold crossed interrupt. + spi->dma |= (MXC_F_SPI_REVA_DMA_TX_FIFO_EN); + spi->inten |= MXC_F_SPI_REVA_INTEN_TX_THD; + + // Set TX Threshold to minimum value after re-enabling TX FIFO. + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, + (1 << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); + } + + if (rx_length_frames > 0) { + // Enable RX FIFO & RX Threshold crossed interrupt. + spi->dma |= (MXC_F_SPI_REVA_DMA_RX_FIFO_EN); + spi->inten |= MXC_F_SPI_REVA_INTEN_RX_THD; + + // Set RX Threshold to minimum value after re-enabling RX FIFO. + MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, + (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); + } + + // This private function, MXC_SPI_RevA2_process, call fills the TX FIFO as much as possible + // before launching the transaction. Subsequent FIFO management will be handled after + // transaction has started. + MXC_SPI_RevA2_process(spi); + } //<<< End of SPI non-DMA transaction setup. +} + +// Helper function that handles the Target Select assertion/deassertion at start of transaction. +// hw_ts_active_pol is either 1 or 0. +static void MXC_SPI_RevA2_handleTSControl(mxc_spi_reva_regs_t *spi, uint8_t deassert, + uint8_t hw_ts_index) +{ + int8_t spi_num; + + // Ensure valid SPI Instance. + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); // Handle target-select (L. SS) deassertion if HW is selected as Target Select (TS) Control Scheme. This must be done // AFTER launching the transaction to avoid a glitch on the TS line if: @@ -1441,350 +1355,242 @@ int MXC_SPI_RevA2_ControllerTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_bu // // As soon as the SPI hardware receives CTRL0->START it seems to reinitialize the Target Select (TS) pin based // on the value of CTRL->SS_CTRL, which causes the glitch. - if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { + if (STATES[spi_num].ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { // In HW Auto Scheme, only use the target index member. // Limitation: This implemention only support transactions with one target at a time. MXC_SETFIELD(spi->ctrl0, MXC_F_SPI_REVA_CTRL0_SS_ACTIVE, - ((1 << target->index) << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS)); + ((1 << hw_ts_index) << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS)); if (deassert) { spi->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_SS_CTRL; } else { spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_SS_CTRL; } - - // Toggle Chip Select Pin if handled by the driver. - } else if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_SW_DRV) { - // Make sure the selected Target Select (L. SS) pin is enabled as an output. - if (target->pins.func != MXC_GPIO_FUNC_OUT) { - return E_BAD_STATE; - } - - // Active HIGH (1). - if (target->active_polarity) { - target->pins.port->out_set |= target->pins.mask; - // Active LOW (0). - } else { - target->pins.port->out_clr |= target->pins.mask; - } } - return E_SUCCESS; + // Add support for SW_DRV TS Control here in the future. } -int MXC_SPI_RevA2_ControllerTransactionB(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, - uint8_t deassert, mxc_spi_target_t *target) -{ - int error; - int spi_num; - - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - - // This function fills in the STATES value for the flags that checks for blocking status. - error = MXC_SPI_RevA2_ControllerTransaction(spi, tx_buffer, tx_fr_len, rx_buffer, rx_fr_len, - deassert, target); - if (error != E_NO_ERROR) { - return error; - } - - // Blocking - while (STATES[spi_num].controller_done == false) {} - - return E_SUCCESS; -} +/* ** Transaction Functions ** */ -int MXC_SPI_RevA2_ControllerTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, - uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target) +int MXC_SPI_RevA2_ControllerTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, uint8_t deassert, + uint8_t hw_ts_index) { - int spi_num, tx_dummy_fr_len; - // For readability purposes. - int rx_ch, tx_ch; + int8_t spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; - } - // Make sure DMA is initialized. - if (STATES[spi_num].init.use_dma == false || STATES[spi_num].dma_initialized == false) { + // Make sure DMA is not initialized. + if (STATES[spi_num].dma_initialized == true) { return E_BAD_STATE; } - // Make sure SPI Instance was initialized. - if (STATES[spi_num].initialized == false) { + // Make sure SPI Instance is in Controller mode (L. Master). + if (STATES[spi_num].controller_target != MXC_SPI_TYPE_CONTROLLER) { return E_BAD_STATE; } - // Initialize SPIn state to handle DMA transactions. - STATES[spi_num].controller_done = false; + // Save target settings. + STATES[spi_num].deassert = deassert; - STATES[spi_num].tx_buffer = tx_buffer; - STATES[spi_num].tx_done = false; + // Setup SPI registers for non-DMA transaction. + MXC_SPI_RevA2_transactionSetup(spi, tx_buffer, tx_length_frames, rx_buffer, rx_length_frames, + false); - STATES[spi_num].rx_buffer = rx_buffer; - STATES[spi_num].rx_done = false; + // Start the SPI transaction. + spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_START; - // Max number of frames to transmit/receive. - if (tx_fr_len > (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)) { - return E_OVERFLOW; - } + // Handle Target Select Pin (Only applicable in HW_AUTO TS control scheme). + MXC_SPI_RevA2_handleTSControl(spi, deassert, hw_ts_index); - if (rx_fr_len > (MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS)) { - return E_OVERFLOW; - } + // Complete transaction once it started. + while (STATES[spi_num].transaction_done == false) { + if (STATES[spi_num].tx_done == true && STATES[spi_num].rx_done == true) { + if (!(spi->stat & MXC_F_SPI_REVA_STAT_BUSY)) { + STATES[spi_num].transaction_done = true; + } + } - // STATES[n] TX/RX Length Fields are in terms of number of bytes to send/receive. - if (STATES[spi_num].init.frame_size <= 8) { - STATES[spi_num].tx_len = tx_fr_len; - STATES[spi_num].rx_len = rx_fr_len; - } else { - STATES[spi_num].tx_len = tx_fr_len * 2; - STATES[spi_num].rx_len = rx_fr_len * 2; + MXC_SPI_RevA2_process(spi); } - STATES[spi_num].deassert = deassert; - STATES[spi_num].current_target = *target; + return E_SUCCESS; +} - // Set the number of bytes to transmit/receive for the SPI transaction. - if (STATES[spi_num].init.mode == MXC_SPI_INTERFACE_STANDARD) { - if (rx_fr_len > tx_fr_len) { - // 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. - tx_dummy_fr_len = rx_fr_len - tx_fr_len; +int MXC_SPI_RevA2_ControllerTransactionAsync(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, uint8_t deassert, + uint8_t hw_ts_index) +{ + int8_t spi_num; - // Check whether new frame length exceeds the possible number of frames to transmit. - if ((tx_fr_len + tx_dummy_fr_len) > - (MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR >> MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS)) { - return E_OVERFLOW; - } + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - spi->ctrl1 = ((tx_fr_len + tx_dummy_fr_len) << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); - } else { - spi->ctrl1 = (tx_fr_len << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS); - } - } else { // mode != MXC_SPI_INTE_STANDARD - spi->ctrl1 = (tx_fr_len << MXC_F_SPI_REVA_CTRL1_TX_NUM_CHAR_POS) | - (rx_fr_len << MXC_F_SPI_REVA_CTRL1_RX_NUM_CHAR_POS); + // Make sure DMA is not initialized. + if (STATES[spi_num].dma_initialized == true) { + return E_BAD_STATE; } - // Disable FIFOs before clearing as recommended by UG. - spi->dma &= ~(MXC_F_SPI_REVA_DMA_TX_FIFO_EN | MXC_F_SPI_REVA_DMA_DMA_TX_EN | - MXC_F_SPI_REVA_DMA_RX_FIFO_EN | MXC_F_SPI_REVA_DMA_DMA_RX_EN); - spi->dma |= (MXC_F_SPI_REVA_DMA_TX_FLUSH | MXC_F_SPI_REVA_DMA_RX_FLUSH); - - // Enable TX FIFO before configuring. - spi->dma |= (MXC_F_SPI_REVA_DMA_TX_FIFO_EN); + // Make sure SPI Instance is in Controller mode (L. Master). + if (STATES[spi_num].controller_target != MXC_SPI_TYPE_CONTROLLER) { + return E_BAD_STATE; + } - // Set TX and RX Thresholds before loading FIFO. - MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, - ((MXC_SPI_FIFO_DEPTH - 1) << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); - MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_RX_THD_VAL, (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); + // Save target settings. + STATES[spi_num].deassert = deassert; - // Set up DMA TX Transactions. - // 1) For TX transmissions. - if (tx_fr_len > 1) { - // For readability purposes. - tx_ch = STATES[spi_num].tx_dma_ch; + // Setup SPI registers for non-DMA transaction. + MXC_SPI_RevA2_transactionSetup(spi, tx_buffer, tx_length_frames, rx_buffer, rx_length_frames, + false); - // Configure DMA TX depending on frame width. - // 2-8 bit wide frames. - if (STATES[spi_num].init.frame_size <= 8) { - // Hardware requires writing the first byte into the FIFO manually. - spi->fifo8[0] = tx_buffer[0]; + // Enable Controller Done Interrupt. + spi->inten |= MXC_F_SPI_REVA_INTEN_MST_DONE; - // Threshold set to 1 frame (1 byte) after pre-loading first byte for DMA. - MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, - (1 << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); + // Start the SPI transaction. + spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_START; - STATES[spi_num].dma->ch[tx_ch].src = (uint32_t)(tx_buffer + 1); // 1 Byte offset - STATES[spi_num].dma->ch[tx_ch].cnt = (tx_fr_len - 1); + // Handle Target Select Pin (Only applicable in HW_AUTO TS control scheme). + MXC_SPI_RevA2_handleTSControl(spi, deassert, hw_ts_index); - // Set to one byte burst size. - MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_BURST_SIZE, - (0 << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS)); + return E_SUCCESS; +} - // Set source and destination width to one byte. - MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, - MXC_S_DMA_REVA_CTRL_SRCWD_BYTE); - MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, - MXC_S_DMA_REVA_CTRL_DSTWD_BYTE); +int MXC_SPI_RevA2_ControllerTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, uint8_t deassert, + uint8_t hw_ts_index, mxc_dma_reva_regs_t *dma) +{ + int8_t spi_num; + int error; - // 9-16 bit wide frames. - } else { - // Hardware requires writing the first bytes into the FIFO manually. - STATES[spi_num].tx_cnt += MXC_SPI_RevA2_writeTXFIFO16( - spi, (uint8_t *)(STATES[spi_num].tx_buffer), STATES[spi_num].tx_len); + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - // Threshold set to 1 frame (2 bytes) after pre-loading FIFO for DMA. - MXC_SETFIELD(spi->dma, MXC_F_SPI_REVA_DMA_TX_THD_VAL, - (2 << MXC_F_SPI_REVA_DMA_TX_THD_VAL_POS)); + // More overhead, but this function will initialize DMA if it wasn't done earlier. + if (STATES[spi_num].dma_initialized == false) { + error = MXC_SPI_RevA2_DMA_Init(spi, dma, true, true); + if (error != E_NO_ERROR) { + return error; + } + } - STATES[spi_num].dma->ch[tx_ch].src = (uint32_t)(tx_buffer + STATES[spi_num].tx_cnt); - STATES[spi_num].dma->ch[tx_ch].cnt = (STATES[spi_num].tx_len - STATES[spi_num].tx_cnt); + // Make sure SPI Instance is in Controller mode (L. Master). + if (STATES[spi_num].controller_target != MXC_SPI_TYPE_CONTROLLER) { + return E_BAD_STATE; + } - // Set to two byte burst size. - MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_BURST_SIZE, - (1 << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS)); + // Save target settings. + STATES[spi_num].deassert = deassert; - // Set source and destination width to two bytes. - MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, - MXC_S_DMA_REVA_CTRL_SRCWD_HALFWORD); - MXC_SETFIELD(STATES[spi_num].dma->ch[tx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, - MXC_S_DMA_REVA_CTRL_DSTWD_HALFWORD); - } + // Setup SPI registers for non-DMA transaction. + MXC_SPI_RevA2_transactionSetup(spi, tx_buffer, tx_length_frames, rx_buffer, rx_length_frames, + true); - STATES[spi_num].dma->ch[tx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_SRCINC; - STATES[spi_num].dma->ch[tx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_EN; // Start the DMA + // Start the SPI transaction. + spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_START; - // 2) For single character transmissions. - // NOTE: Single-length transmissions does not trigger CTZ. - } else if (tx_fr_len == 1) { - // Write first frame into FIFO. - if (STATES[spi_num].init.frame_size <= 8) { - spi->fifo8[0] = tx_buffer[0]; - } else { - MXC_SPI_RevA2_writeTXFIFO16(spi, (uint8_t *)(STATES[spi_num].tx_buffer), 2); - } + // Handle Target Select Pin (Only applicable in HW_AUTO TS control scheme). + MXC_SPI_RevA2_handleTSControl(spi, deassert, hw_ts_index); - // If there is no RX DMA and only one frame is transmitted, then - // the transaction is done. Single-length transmissions - // does not trigger a CTZ interrupt. - if (rx_fr_len > 0 && rx_buffer != NULL) { - STATES[spi_num].controller_done = true; - } + return E_SUCCESS; +} - STATES[spi_num].tx_done = true; +int MXC_SPI_RevA2_TargetTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames) +{ + int8_t spi_num; - // 3) Set up DMA TX for RX only transactions. - // Note: Even if you are not transmitting anything in standard 4-wire mode, - // the hardware always assume full duplex. Therefore dummy bytes - // must be transmitted to support half duplex. The number of bytes to transmit - // AND receive is set by TX_NUM_CHAR, and the RX_NUM_CHAR field of ctrl1 is ignored. - } else if (tx_fr_len == 0 && STATES[spi_num].init.mode == MXC_SPI_INTERFACE_STANDARD) { - // For readability purposes. - tx_ch = STATES[spi_num].tx_dma_ch; + // Ensure valid SPI Instance. + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - // Configure TX DMA channel to retransmit the dummy byte. - STATES[spi_num].dma->ch[tx_ch].src = (uint32_t)(&(STATES[spi_num].tx_dummy_value)); - STATES[spi_num].dma->ch[tx_ch].cnt = STATES[spi_num].rx_len; // Only receiving - STATES[spi_num].dma->ch[tx_ch].ctrl &= ~MXC_F_DMA_REVA_CTRL_SRCINC; - STATES[spi_num].dma->ch[tx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_EN; // Start the DMA + // Make sure DMA is not initialized. + if (STATES[spi_num].dma_initialized == true) { + return E_BAD_STATE; } - // Enable SPI TX DMA after configuring. - spi->dma |= (MXC_F_SPI_REVA_DMA_DMA_TX_EN); - - // Set up DMA RX Transactions. - if (rx_fr_len > 0 && rx_buffer != NULL) { - // For readability purposes. - rx_ch = STATES[spi_num].rx_dma_ch; - - // Enable RX DMA channel before configuring. - spi->dma |= (MXC_F_SPI_REVA_DMA_RX_FIFO_EN); + // Make sure SPI Instance is in Target mode (L. Slave). + if (STATES[spi_num].controller_target != MXC_SPI_TYPE_TARGET) { + return E_BAD_STATE; + } - STATES[spi_num].dma->ch[rx_ch].dst = (uint32_t)rx_buffer; - STATES[spi_num].dma->ch[rx_ch].cnt = STATES[spi_num].rx_len; + // Setup SPI registers for non-DMA transaction. + MXC_SPI_RevA2_transactionSetup(spi, tx_buffer, tx_length_frames, rx_buffer, rx_length_frames, + false); - // Set to one byte burst size. - MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_BURST_SIZE, - (0 << MXC_F_DMA_REVA_CTRL_BURST_SIZE_POS)); + // Wait for Target Select pin to be asserted before starting transaction. + while ((spi->stat & MXC_F_SPI_REVA_STAT_BUSY) == 0) {} - // Match frame size (in terms of bytes) in DMA ctrl settings. - if (STATES[spi_num].init.frame_size <= 8) { - // Set source and destination width to one byte - MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, - MXC_S_DMA_REVA_CTRL_SRCWD_BYTE); - MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, - MXC_S_DMA_REVA_CTRL_DSTWD_BYTE); - } else { - // Set source destination width to 2 bytes - MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_SRCWD, - MXC_S_DMA_REVA_CTRL_SRCWD_HALFWORD); - MXC_SETFIELD(STATES[spi_num].dma->ch[rx_ch].ctrl, MXC_F_DMA_REVA_CTRL_DSTWD, - MXC_S_DMA_REVA_CTRL_DSTWD_HALFWORD); + // Complete transaction once started. + while (STATES[spi_num].transaction_done == false) { + if (STATES[spi_num].tx_count_bytes == STATES[spi_num].tx_length_bytes && + STATES[spi_num].rx_count_bytes == STATES[spi_num].rx_length_bytes) { + STATES[spi_num].transaction_done = true; } - STATES[spi_num].dma->ch[rx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_DSTINC; - STATES[spi_num].dma->ch[rx_ch].ctrl |= MXC_F_DMA_REVA_CTRL_EN; // Start the DMA - - // Enable SPI RX DMA after configuring. - spi->dma |= (MXC_F_SPI_REVA_DMA_DMA_RX_EN); + MXC_SPI_RevA2_process(spi); } - // Start the SPI transaction. - spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_START; + // Wait until transaction is complete. + while (spi->stat & MXC_F_SPI_REVA_STAT_BUSY) {} - // Handle target-select (L. SS) deassertion. This must be done AFTER launching the transaction - // to avoid a glitch on the TS line if: - // - The TS 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 TS pin based - // on the value of CTRL->SS_CTRL, which causes the glitch. - if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { - // In HW Auto Scheme, only use the target index member. - MXC_SETFIELD(spi->ctrl0, MXC_F_SPI_REVA_CTRL0_SS_ACTIVE, - ((1 << target->index) << MXC_F_SPI_REVA_CTRL0_SS_ACTIVE_POS)); + return E_SUCCESS; +} - if (deassert) { - spi->ctrl0 &= ~MXC_F_SPI_REVA_CTRL0_SS_CTRL; - } else { - spi->ctrl0 |= MXC_F_SPI_REVA_CTRL0_SS_CTRL; - } +int MXC_SPI_RevA2_TargetTransactionAsync(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames) +{ + int8_t spi_num; - // Toggle Chip Select Pin if handled by the driver. - } else if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_SW_DRV) { - // Make sure the selected Target Select (L. SS) pin is enabled as an output. - if (target->pins.func != MXC_GPIO_FUNC_OUT) { - return E_BAD_STATE; - } + // Ensure valid SPI Instance. + spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - // Active HIGH (1). - if (target->active_polarity) { - target->pins.port->out_set |= target->pins.mask; - // Active LOW (0). - } else { - target->pins.port->out_clr |= target->pins.mask; - } + // Make sure DMA is not initialized. + if (STATES[spi_num].dma_initialized == true) { + return E_BAD_STATE; } + // Make sure SPI Instance is in Target mode (L. Slave). + if (STATES[spi_num].controller_target != MXC_SPI_TYPE_TARGET) { + return E_BAD_STATE; + } + + // Setup SPI registers for non-DMA transaction. + MXC_SPI_RevA2_transactionSetup(spi, tx_buffer, tx_length_frames, rx_buffer, rx_length_frames, + false); + return E_SUCCESS; } -int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, - uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target) +int MXC_SPI_RevA2_TargetTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, mxc_dma_reva_regs_t *dma) { + int8_t spi_num; int error; - int spi_num; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - if (spi_num < 0 || spi_num >= MXC_SPI_INSTANCES) { - return E_BAD_PARAM; + + // More overhead, but this function will initialize DMA if it wasn't done earlier. + if (STATES[spi_num].dma_initialized == false) { + error = MXC_SPI_RevA2_DMA_Init(spi, dma, true, true); + if (error != E_NO_ERROR) { + return error; + } } - // This function fills in the STATES value for the flags that checks for blocking status. - error = MXC_SPI_RevA2_ControllerTransactionDMA(spi, tx_buffer, tx_fr_len, rx_buffer, rx_fr_len, - deassert, target); - if (error != E_NO_ERROR) { - return error; + // Make sure SPI Instance is in Target mode (L. Slave). + if (STATES[spi_num].controller_target != MXC_SPI_TYPE_TARGET) { + return E_BAD_STATE; } - // Blocking - while (((STATES[spi_num].controller_done == false && STATES[spi_num].tx_done == false) && - !(STATES[spi_num].tx_buffer != NULL && STATES[spi_num].tx_len > 0)) && - (STATES[spi_num].rx_done == false && - !(STATES[spi_num].rx_buffer != NULL && STATES[spi_num].rx_len > 0))) {} + // Setup SPI registers for DMA transaction. + MXC_SPI_RevA2_transactionSetup(spi, tx_buffer, tx_length_frames, rx_buffer, rx_length_frames, + true); + // Target transaction is ready. return E_SUCCESS; } @@ -1792,31 +1598,15 @@ int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *t void MXC_SPI_RevA2_Handler(mxc_spi_reva_regs_t *spi) { - int spi_num; + int8_t spi_num; uint32_t status = spi->intfl; - // Used later for readability purposes on handling Chip Select. - mxc_gpio_regs_t *target_port; - uint32_t target_mask; - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); // Master done (TX complete) if (status & MXC_F_SPI_REVA_INTFL_MST_DONE) { spi->intfl |= MXC_F_SPI_REVA_INTFL_MST_DONE; // Clear flag - // Toggle Target Select (TS) Pin if Driver is handling it. - if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_SW_DRV) { - if (STATES[spi_num].deassert == true) { - // Readability for handling Chip Select. - target_port = STATES[spi_num].current_target.pins.port; - target_mask = STATES[spi_num].current_target.pins.mask; - - target_port->out ^= target_mask; - } // Don't deassert the Target Select (TS) pin if false for multiple repeated transactions. - } - // Callback if valid. // Note: If Target Select (TS) Control Scheme is set in SW_App mode, then the caller needs to ensure the // Target Select (TS) pin is asserted or deasserted in their application. @@ -1825,40 +1615,33 @@ void MXC_SPI_RevA2_Handler(mxc_spi_reva_regs_t *spi) } // Controller is done after callback (if valid) is handled. - STATES[spi_num].controller_done = true; + STATES[spi_num].transaction_done = true; } // Handle RX Threshold if (status & MXC_F_SPI_REVA_INTFL_RX_THD) { spi->intfl |= MXC_F_SPI_REVA_INTFL_RX_THD; - if (STATES[spi_num].init.use_dma == false) { - // RX threshold has been crossed, there's data to unload from the FIFO - MXC_SPI_RevA2_process(spi); - } + + // RX threshold has been crossed, there's data to unload from the FIFO + MXC_SPI_RevA2_process(spi); } // Handle TX Threshold if (status & MXC_F_SPI_REVA_INTFL_TX_THD) { spi->intfl |= MXC_F_SPI_REVA_INTFL_TX_THD; - if (STATES[spi_num].init.use_dma == false) { - // TX threshold has been crossed, we need to refill the FIFO - MXC_SPI_RevA2_process(spi); - } + + // TX threshold has been crossed, we need to refill the FIFO + MXC_SPI_RevA2_process(spi); } } void MXC_SPI_RevA2_DMA_TX_Handler(mxc_spi_reva_regs_t *spi) { - int spi_num; + int8_t spi_num; uint32_t tx_ch; uint32_t status; - // Used later for readability purposes on handling Chip Select. - mxc_gpio_regs_t *target_port; - uint32_t target_mask; - spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); tx_ch = STATES[spi_num].tx_dma_ch; status = STATES[spi_num].dma->ch[tx_ch].status; @@ -1869,18 +1652,7 @@ void MXC_SPI_RevA2_DMA_TX_Handler(mxc_spi_reva_regs_t *spi) STATES[spi_num].dma->ch[tx_ch].status |= MXC_F_DMA_REVA_STATUS_CTZ_IF; // For completeness-sake. - STATES[spi_num].tx_cnt = STATES[spi_num].tx_len; - - // Toggle Target Select (TS) Pin if Driver is handling it. - if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_SW_DRV) { - if (STATES[spi_num].deassert == true) { - // Readability for handling Chip Select. - target_port = STATES[spi_num].current_target.pins.port; - target_mask = STATES[spi_num].current_target.pins.mask; - - target_port->out ^= target_mask; - } // Don't deassert the Target Select (TS) pin if false for multiple repeated transactions. - } + STATES[spi_num].tx_count_bytes = STATES[spi_num].tx_length_bytes; // Callback if valid and if you're only transmitting. // Note: If Target Select (TS) Control Scheme is set in SW_App mode, then the caller needs to ensure the @@ -1892,8 +1664,8 @@ void MXC_SPI_RevA2_DMA_TX_Handler(mxc_spi_reva_regs_t *spi) } // TX Transaction is done if there's no RX transaction. - if (STATES[spi_num].rx_len == 0 || STATES[spi_num].tx_buffer == NULL) { - STATES[spi_num].controller_done = true; + if (STATES[spi_num].rx_length_bytes == 0 || STATES[spi_num].tx_buffer == NULL) { + STATES[spi_num].transaction_done = true; } } @@ -1905,15 +1677,11 @@ void MXC_SPI_RevA2_DMA_TX_Handler(mxc_spi_reva_regs_t *spi) void MXC_SPI_RevA2_DMA_RX_Handler(mxc_spi_reva_regs_t *spi) { - int spi_num; + int8_t spi_num; uint32_t rx_ch; uint32_t status; - // Used later for readability purposes on handling Chip Select. - mxc_gpio_regs_t *target_port; - uint32_t target_mask; spi_num = MXC_SPI_GET_IDX((mxc_spi_regs_t *)spi); - MXC_ASSERT(spi_num >= 0); rx_ch = STATES[spi_num].rx_dma_ch; status = STATES[spi_num].dma->ch[rx_ch].status; @@ -1923,26 +1691,15 @@ void MXC_SPI_RevA2_DMA_RX_Handler(mxc_spi_reva_regs_t *spi) // HW Bug: For 2-byte wide frame transactions, RX DMA swaps the // LSB and MSB. // Example: TX: 0x1234 => RX: 0x3412 - if (STATES[spi_num].init.frame_size > 8) { - MXC_SPI_RevA2_DMA_SwapByte(STATES[spi_num].rx_buffer, STATES[spi_num].rx_len); + if (STATES[spi_num].frame_size > 8) { + MXC_SPI_RevA2_DMA_SwapByte(STATES[spi_num].rx_buffer, STATES[spi_num].rx_length_bytes); } STATES[spi_num].rx_done = 1; STATES[spi_num].dma->ch[rx_ch].status |= MXC_F_DMA_STATUS_CTZ_IF; - // Toggle Target Select (TS) Pin if Driver is handling it. - if (STATES[spi_num].init.ts_control == MXC_SPI_TSCONTROL_SW_DRV) { - if (STATES[spi_num].deassert == true) { - // Readability for handling Chip Select. - target_port = STATES[spi_num].current_target.pins.port; - target_mask = STATES[spi_num].current_target.pins.mask; - - target_port->out ^= target_mask; - } // Don't deassert the Target Select (TS) pin if false for multiple repeated transactions. - } - // For completeness-sake. - STATES[spi_num].rx_cnt = STATES[spi_num].rx_len; + STATES[spi_num].rx_count_bytes = STATES[spi_num].rx_length_bytes; // Callback if valid. // Note: If Target Select (TS) Control Scheme is set in SW_App mode, then the caller needs to ensure the @@ -1952,8 +1709,8 @@ void MXC_SPI_RevA2_DMA_RX_Handler(mxc_spi_reva_regs_t *spi) } // RX transaction determines the controller is done if TX transaction is also present. - if (STATES[spi_num].tx_len > 0 && STATES[spi_num].tx_buffer != NULL) { - STATES[spi_num].controller_done = true; + if (STATES[spi_num].tx_length_bytes > 0 && STATES[spi_num].tx_buffer != NULL) { + STATES[spi_num].transaction_done = true; } } diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h index 58c3916bced..693a622e3fc 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h @@ -54,7 +54,10 @@ extern "C" { /* **** Functions **** */ -int MXC_SPI_RevA2_Init(mxc_spi_init_t *init); +int MXC_SPI_RevA2_Init(mxc_spi_reva_regs_t *spi, mxc_spi_type_t controller_target, + mxc_spi_interface_t if_mode, uint32_t freq, uint8_t ts_active_pol_mask); + +int MXC_SPI_RevA2_Config(mxc_spi_cfg_t *cfg); int MXC_SPI_RevA2_Shutdown(mxc_spi_reva_regs_t *spi); @@ -66,6 +69,10 @@ void MXC_SPI_RevA2_EnableInt(mxc_spi_reva_regs_t *spi, uint32_t en); void MXC_SPI_RevA2_DisableInt(mxc_spi_reva_regs_t *spi, uint32_t dis); +int MXC_SPI_RevA2_SetTSControl(mxc_spi_reva_regs_t *spi, mxc_spi_tscontrol_t ts_control); + +mxc_spi_tscontrol_t MXC_SPI_RevA2_GetTSControl(mxc_spi_reva_regs_t *spi); + int MXC_SPI_RevA2_SetFrequency(mxc_spi_reva_regs_t *spi, uint32_t freq); int MXC_SPI_RevA2_GetFrequency(mxc_spi_reva_regs_t *spi); @@ -74,7 +81,7 @@ int MXC_SPI_RevA2_SetFrameSize(mxc_spi_reva_regs_t *spi, int frame_size); int MXC_SPI_RevA2_GetFrameSize(mxc_spi_reva_regs_t *spi); -int MXC_SPI_RevA2_SetInterface(mxc_spi_reva_regs_t *spi, mxc_spi_interface_t mode); +int MXC_SPI_RevA2_SetInterface(mxc_spi_reva_regs_t *spi, mxc_spi_interface_t if_mode); mxc_spi_interface_t MXC_SPI_RevA2_GetInterface(mxc_spi_reva_regs_t *spi); @@ -84,10 +91,6 @@ mxc_spi_clkmode_t MXC_SPI_RevA2_GetClkMode(mxc_spi_reva_regs_t *spi); int MXC_SPI_RevA2_SetCallback(mxc_spi_reva_regs_t *spi, mxc_spi_callback_t callback, void *data); -int MXC_SPI_RevA2_SetInitStruct(mxc_spi_reva_regs_t *spi, mxc_spi_init_t *init); - -mxc_spi_init_t MXC_SPI_RevA2_GetInitStruct(mxc_spi_reva_regs_t *spi); - int MXC_SPI_RevA2_GetActive(mxc_spi_reva_regs_t *spi); int MXC_SPI_RevA2_ReadyForSleep(mxc_spi_reva_regs_t *spi); @@ -116,7 +119,8 @@ uint8_t MXC_SPI_RevA2_GetRXThreshold(mxc_spi_reva_regs_t *spi); /* ** DMA-Specific Functions ** */ -int MXC_SPI_RevA2_DMA_Init(mxc_spi_init_t *init); +int MXC_SPI_RevA2_DMA_Init(mxc_spi_reva_regs_t *spi, mxc_dma_reva_regs_t *dma, bool use_dma_tx, + bool use_dma_rx); bool MXC_SPI_RevA2_DMA_GetInitialized(mxc_spi_reva_regs_t *spi); @@ -132,22 +136,31 @@ void MXC_SPI_RevA2_DMA_SwapByte(uint8_t *buffer, uint32_t len_bytes); /* ** Transaction Functions ** */ int MXC_SPI_RevA2_ControllerTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, - uint8_t deassert, mxc_spi_target_t *target); + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, uint8_t deassert, + uint8_t hw_ts_index); -int MXC_SPI_RevA2_ControllerTransactionB(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, - uint8_t deassert, mxc_spi_target_t *target); +int MXC_SPI_RevA2_ControllerTransactionAsync(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, uint8_t deassert, + uint8_t hw_ts_index); int MXC_SPI_RevA2_ControllerTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, - uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target); - -int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, - uint32_t tx_fr_len, uint8_t *rx_buffer, - uint32_t rx_fr_len, uint8_t deassert, - mxc_spi_target_t *target); + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, uint8_t deassert, + uint8_t hw_ts_index, mxc_dma_reva_regs_t *dma); + +int MXC_SPI_RevA2_TargetTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames); + +int MXC_SPI_RevA2_TargetTransactionAsync(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames); + +int MXC_SPI_RevA2_TargetTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer, + uint32_t tx_length_frames, uint8_t *rx_buffer, + uint32_t rx_length_frames, mxc_dma_reva_regs_t *dma); /* ** Handler Functions ** */ diff --git a/Libraries/PeriphDrivers/max78002_files.mk b/Libraries/PeriphDrivers/max78002_files.mk index a7be7da63d8..0faf01cac44 100644 --- a/Libraries/PeriphDrivers/max78002_files.mk +++ b/Libraries/PeriphDrivers/max78002_files.mk @@ -136,17 +136,25 @@ PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SDHC/sdhc_ai87.c PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SDHC/sdhc_reva.c USE_NATIVE_SDHC = yes -MXC_SPI_LEGACY?=0 +MXC_SPI_VERSION ?= v1 +# Selects the SPI drivers to build with. Acceptable values are: +# - v1 +# - v2 PERIPH_DRIVER_INCLUDE_DIR += $(SOURCE_DIR)/SPI -export MXC_SPI_LEGACY -ifeq ($(MXC_SPI_LEGACY),1) -# Legacy SPI Implementation +export MXC_SPI_VERSION +ifeq ($(MXC_SPI_VERSION),v1) +# SPI v1 (Legacy) Implementation PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SPI/spi_ai87.c PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SPI/spi_reva1.c +PROJ_CFLAGS+=-DMXC_SPI_V1 else +ifeq ($(MXC_SPI_VERSION),v2) # SPI v2 Implementation PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SPI/spi_ai87_v2.c PERIPH_DRIVER_C_FILES += $(SOURCE_DIR)/SPI/spi_reva2.c +else +$(error Invalid value for MXC_SPI_VERSION = "$(MXC_SPI_VERSION)" Acceptable values are "v1" or "v2") +endif endif PERIPH_DRIVER_INCLUDE_DIR += $(SOURCE_DIR)/TRNG diff --git a/USERGUIDE.md b/USERGUIDE.md index 9f3fc909582..eade9000534 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -1896,6 +1896,14 @@ The following variables can be used to enable the [available libraries](#librari | `LIB_SDHC` | Include the SDHC library | This option toggles the Secure Digital High Capacity (SDHC) library, which can be used to interface with SD cards. Additionally, it enables the [FatFS](http://elm-chan.org/fsw/ff/00index_e.html) library, which implements a generic FAT filesystem. | | `LIB_CLI` | Include the MSDK's built-in CLI library | This option toggles the MSDK's built-in CLI library, which can be used to process received commands over UART. | +#### Build Variables for the PeriphDrivers Library + +The following variables are specific to the PeriphDrivers library. + +| Configuration Variable | Description | Details | +| ---------------------- | ---------------------------------------------------------- | ------------------------------------------------------------ | +| `MXC_SPI_VERSION` | Set the SPI drivers to use (default is `v1`) | The PeriphDrivers offer two versions of the SPI API in order to maintain backwards compatibility. Acceptable values are `v1` (legacy) or `v2`. See [The SPI V2 Developer Note](#spi-v2-library) for more details. | + #### Build Variables for Secure Boot Tools (SBTs) For microcontrollers with a secure bootloader, the following build configuration variables can be used to enable integration with the Secure Boot Tools. These are a suite of applications designed for use with microcontrollers that have secure bootloaders. @@ -2451,13 +2459,158 @@ For VS Code users, the `"erase flash"` [build task](#build-tasks) can be used to 7. Create an empty file called `erase.act`. -7. Drag and drop the `erase.act` file onto the `DAPLINK` drive. +8. Drag and drop the `erase.act` file onto the `DAPLINK` drive. ![Drag and Drop erase.act](res/erase.act.jpg) -8. The PICO debugger will attempt to mass erase the microcontroller's flash bank, which will completely wipe any application firmware that is programmed on the device. +9. The PICO debugger will attempt to mass erase the microcontroller's flash bank, which will completely wipe any application firmware that is programmed on the device. ???+ note "ℹ️ **Note**" If this process fails, a `FAIL.TXT` file will be present in the DAPLINK drive with an additional error message inside of it. A failure is generally indicative of firmware that has completely shut down the debug port, or has entered low power loop immediately on power-up. In these cases, it's not possible to recover the device. -9. Power cycle the microcontroller. It step 8 succeeded, it's blank and ready to re-program. The debugger should have no issues connecting to the device in this blank state. +10. Power cycle the microcontroller. It step 8 succeeded, it's blank and ready to re-program. The debugger should have no issues connecting to the device in this blank state. + +## Developer Notes + +### SPI v2 Library + +The SPI v2 Library is the latest version of the MSDK SPI drivers which highlights: + +- Target Select (TS) Control Scheme which provides users the option to drive their own TS pins. +- Optional`MXC_SPI_Config(...)` and `mxc_spi_cfg_t` struct to reduce the use of multiple functions to select proper SPI settings. +- Re-mapped the `MXC_SPI_Init(...)` function input parameters (same behavior as SPI v1). +- Allow for re-arming an SPI transaction within the callback function for chained SPI messages. +- Decrease in setup overhead in a Transaction function call. Less nested function calls within drivers. +- Improved SPI DMA support and DMA Channel IRQ vector flexibility by providing acquired DMA channel numbers before a SPI DMA transaction call. +- The use of Controller and Target terms instead of Master and Slave, respectively. +- Still supports SPI v1 function prototypes for backwards-compatibility. +- Bug fixes from the SPI v1 API. + +#### Porting Projects to use SPI v2 + +The latest SPI examples in the MSDK defaults to build the SPI v1 libraries. Set the `MXC_SPI_VERSION` [build configuration variable](#build-configuration-variables) to `v2` (case sensitive) use the SPI v2 API. + +This guide shows how to update an existing project that is using the SPI v1 API to SPI v2. The SPI v2 Library still supports the SPI v1 function prototypes for backwards-compatibility with the main difference being the SPI DMA interrupt handling (see [SPI DMA Interrupt Handling](#spi-dma-interrupt-handling) section below for more info). + +Note: The SPI v2 API is only a drop in replacement to SPI v1 if SPI DMA is **not** used; should the user choose to continue building with the SPI v1 convention but with the underlying SPI v2 implementation. This porting guide demonstrates how to use the full extent of the SPI v2 features. + +##### SPI Init Function + +The input parameters for the `MXC_SPI_Init(...)` function were updated in SPI v2 to allow for more user-selectable options during initialization. This should not cause any errors or behavioral differences with the `MXC_SPI_Init(...)` function when switching between SPI v1 and SPI v2 builds as the input parameters were essentially re-mapped to more descriptive names. + +SPI v1: + + :::C + int MXC_SPI_Init(mxc_spi_regs_t *spi, + int masterMode, + int quadModeUsed, + int numSlaves, + unsigned ssPolarity, + unsigned int hz, + mxc_spi_pins_t pins) + +SPI v2: + + :::C + int MXC_SPI_Init(mxc_spi_regs_t *spi, + mxc_spi_type_t controller_target, + mxc_spi_interface_t if_mode, + int numTargets, + uint8_t ts_active_pol_mask, + uint32_t freq, + mxc_spi_pins_t pins) + +Input Parameters: + +- `mxc_spi_regs_t *spi` remains unchanged. +- `int masterMode` -> `mxc_spi_type_t controller_target`. The enum `mxc_spi_type_t` was added for increased code readability. +- `int quadModeUsed` -> `mxc_spi_interface_t if_mode`. Previously, the `MXC_SPI_Init(...)` function could only select between standard (4wire) and quad interface modes. With SPI v2, the user can select either standard (`MXC_SPI_INTERFACE_STANDARD`), quad (`MXC_SPI_INTERFACE_QUAD`), 3wire (`MXC_SPI_INTERFACE_3WIRE`), or dual (`MXC_SPI_INTERFACE_DUAL`) mode. +- `int numSlaves` -> `int numTargets`. SPI v2 does not use this parameter and was kept to continue supporting SPI v1. +- `unsigned ssPolarity` -> `uint8_t ts_active_pol_mask`. Updated to a more descriptive name. +- `unsigned int hz` -> `uint32_t freq`. +- `mxc_spi_pins_t pins` remains unchanged. + +##### SPI Config Function + +The `int MXC_SPI_Config(mxc_spi_cfg_t cfg)` function was added to reduce the number of helper function calls to set the appropriate settings that the `MXC_SPI_Init(...)` function did not set. + +This function also sets up the DMA and acquires DMA TX/RX channels for SPI DMA transactions. + +`mxc_spi_cfg_t` struct: + +- `mxc_spi_regs_t *spi` - Select SPI Instance to configure. +- `mxc_spi_clkmode_t clk_mode` - Select clock mode. +- `uint8_t frame_size` - Select single frame size (2 - 16 bits). +- `bool use_dma_tx` - Enable SPI DMA TX (acquire and configure TX channel). +- `bool use_dma_rx` - Enable SPI DMA RX (acquire and configure RX channel). +- `mxc_dma_regs_t *dma` - Select DMA Instance to configure for SPI DMA (Valid only if `use_dma_tx` or `use_dma_rx` is set to true). + +##### SPI Request Struct + +`mxc_spi_req_t` struct: + +- `mxc_spi_regs_t *spi` - Remains unchanged. +- `int ssIdx` - Remains unchanged. +- `int ssDeassert` - Remains unchanged. +- `uint8_t *txData` - Remains unchanged. +- `uint8_t *rxData` - Remains unchanged. +- `uint32_t txLen` - Remains unchanged. +- `uint32_t rxLen` - Remains unchanged. +- `uint32_t txCnt` - Not used in SPI v2. +- `uint32_t rxCnt` - Not used in SPI v2. +- `mxc_spi_callback_t completeCB` - Type was renamed, but funtionally, remains unchanged. + +##### SPI Transaction Functions + +The SPI v2 Libraries follows the terms used in the user guide: Controller and Target instead of Master and Slave, respectively. + +- `MXC_SPI_MasterTransaction(...)` -> `MXC_SPI_ControllerTransaction(...)` +- `MXC_SPI_MasterTransactionAsync(...)` -> `MXC_SPI_ControllerTransactionAsync(...)` +- `MXC_SPI_MasterTransactionDMA(...)` -> `MXC_SPI_ControllerTransactionDMA(...)` +- `MXC_SPI_SlaveTransaction(...)` -> `MXC_SPI_TargetTransaction(...)` +- `MXC_SPI_SlaveTransactionAsync(...)` -> `MXC_SPI_TargetTransactionAsync(...)` +- `MXC_SPI_SlaveTransactionDMA(...)` -> `MXC_SPI_TargetTransactionDMA(...)` + +##### SPI DMA Setup for `MXC_SPI_ControllerTransactionDMA(...)` + +The SPI v2 library allows for more flexibility in setting generic DMA TX/RX channel vectors for SPI DMA transactions during run-time. Compared to SPI v1 where the user must know the acquired SPI DMA TX/RX channel numbers and define the appropriate DMA channel handlers before compile-time. + +There are two ways to initialize and configure the DMA before starting a SPI DMA transaction. + +Method 1: Call `int MXC_SPI_DMA_Init(mxc_spi_regs_t *spi, mxc_dma_regs_t *dma, bool use_dma_tx, bool use_dma_rx)`. + +Method 2: Set up the DMA options in the `mxc_spi_cfg_t` struct and call `int MXC_SPI_Config(mxc_spi_cfg_t cfg)`. + + :::C + ... + // Initialize SPI DMA ahead of time. + MXC_SPI_DMA_Init(SPI, DMA, true, true); + + int TX_DMA_CH = MXC_SPI_DMA_GetTXChannel(SPI); + int RX_DMA_CH = MXC_SPI_DMA_GetRXChannel(SPI); + + NVIC_EnableIRQ(MXC_DMA_CH_GET_IRQ(TX_DMA_CH)); + NVIC_EnableIRQ(MXC_DMA_CH_GET_IRQ(RX_DMA_CH)); + + MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(TX_DMA_CH), DMA_TX_IRQHandler); + MXC_NVIC_SetVector(MXC_DMA_CH_GET_IRQ(RX_DMA_CH), DMA_RX_IRQHandler); + + MXC_SPI_ControllerTransactionDMA(&req); + ... + +The DMA is initialized in `MXC_SPI_DMA_Init(...)` or `MXC_SPI_Config(...)`. This provides information on what DMA channels were acquired for a SPI instance's TX and RX DMA before calling the DMA transaction function. Following the example above, it is recommended to set up a generic-named DMA TX/RX vector because the SPI TX and RX DMA channels won't always acquire DMA_CH0 and DMA_CH1, respectively. + +##### SPI DMA Interrupt Handling + + :::C + void DMA_TX_IRQHandler(void) + { + MXC_SPI_DMA_TX_Handler(SPI); + } + + void DMA_RX_IRQHandler(void) + { + MXC_SPI_DMA_RX_Handler(SPI); + } + +The SPI v1 API requires `MXC_DMA_Handler()` to be called in the TX and RX DMA Channel interrupt handlers. Following the generic vector names used in the previous section, the SPI v2 supplies its own TX/RX DMA Handler processing functions (`MXC_SPI_DMA_RX_Handler(...)` and `MXC_SPI_DMA_RX_Handler(...)`) that must be called within their appropriate DMA channel interrupt handlers.