From a6e6cde1ef599e54dcde9fc4777f2cb785b7352a Mon Sep 17 00:00:00 2001 From: Sihyung Woo Date: Tue, 11 Jul 2023 15:46:16 -0500 Subject: [PATCH 01/85] feat(PeriphDrivers): Add SPI Target Transaction functions --- .../PeriphDrivers/Include/MAX78002/spi.h | 32 ++ .../PeriphDrivers/Source/SPI/spi_ai87_v2.c | 60 ++- .../PeriphDrivers/Source/SPI/spi_reva2.c | 381 +++++++++++++++++- .../PeriphDrivers/Source/SPI/spi_reva2.h | 8 + 4 files changed, 462 insertions(+), 19 deletions(-) diff --git a/Libraries/PeriphDrivers/Include/MAX78002/spi.h b/Libraries/PeriphDrivers/Include/MAX78002/spi.h index b02e92e1ae..41069c2546 100644 --- a/Libraries/PeriphDrivers/Include/MAX78002/spi.h +++ b/Libraries/PeriphDrivers/Include/MAX78002/spi.h @@ -1039,6 +1039,38 @@ int MXC_SPI_SlaveTransactionAsync(mxc_spi_req_t *req); */ int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req); +/** + * @brief Setup an interrupt-driven, non-blocking SPI Target 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. + * + * @return See \ref MXC_Error_Codes for the list of error return codes. + */ +int MXC_SPI_TargetTransaction(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); + +/** + * @brief Setup a DMA driven SPI Target 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. + * + * @return See \ref MXC_Error_Codes for the list of error return codes. + */ +int MXC_SPI_TargetTransactionDMA(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); + /* ** Handler Functions ** */ /** diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c b/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c index 455fb777b4..0d99cf6719 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c @@ -774,8 +774,8 @@ int MXC_SPI_MasterTransactionAsync(mxc_spi_req_t *req) } 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); + req->tx_len, req->rx_buffer, req->rx_len, + req->deassert, &target); } int MXC_SPI_MasterTransactionDMA(mxc_spi_req_t *req) @@ -866,12 +866,64 @@ int MXC_SPI_SlaveTransaction(mxc_spi_req_t *req) int MXC_SPI_SlaveTransactionAsync(mxc_spi_req_t *req) { - return E_NOT_SUPPORTED; + int error; + + error = MXC_SPI_SetCallback(req->spi, req->callback, req->callback_data); + if (error != E_NO_ERROR) { + return error; + } + + return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, req->tx_len, req->rx_buffer, req->rx_len, req->deassert); } int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req) { - return E_NOT_SUPPORTED; + int error; + mxc_spi_init_t init; + + init.use_dma = true; + init.dma = MXC_DMA; + + // 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); + if (error != E_NO_ERROR) { + return error; + } + } + + error = MXC_SPI_SetCallback(req->spi, req->callback, req); + if (error != E_NO_ERROR) { + return error; + } + + error = MXC_SPI_DMA_SetRequestSelect(req->spi, req->tx_buffer, req->rx_buffer); + if (error != E_NO_ERROR) { + return error; + } + + return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, req->tx_len, req->rx_buffer, req->rx_len, req->deassert); +} + +int MXC_SPI_TargetTransaction(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) +{ + return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, + rx_buffer, rx_fr_len, deassert); +} + +int MXC_SPI_TargetTransactionDMA(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) +{ + int error; + + error = MXC_SPI_DMA_SetRequestSelect(spi, tx_buffer, rx_buffer); + if (error != E_NO_ERROR) { + return error; + } + + return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, + rx_buffer, rx_fr_len, deassert); } /* ** Handler Functions ** */ diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c index 8f6b87e730..71485c39bf 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c @@ -77,8 +77,7 @@ 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; @@ -325,10 +324,9 @@ 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; } @@ -369,6 +367,13 @@ int MXC_SPI_RevA2_Init(mxc_spi_init_t *init) STATES[spi_num].dma = NULL; STATES[spi_num].current_target = *target; + // Only supported TSCONTROL mode for Targets is Hardware (Automatic) Controlled. + if (init->type == MXC_SPI_TYPE_TARGET) { // L. Slave + if (init->ts_control != MXC_SPI_TSCONTROL_HW_AUTO) { + return E_BAD_PARAM; + } + } + // Set up Target Select Control Scheme. // Hardware (Automatic) Controlled. if (init->ts_control == MXC_SPI_TSCONTROL_HW_AUTO) { @@ -390,8 +395,8 @@ int MXC_SPI_RevA2_Init(mxc_spi_init_t *init) } 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)); + ((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. @@ -487,7 +492,7 @@ int MXC_SPI_RevA2_Init(mxc_spi_init_t *init) (0 << MXC_F_SPI_REVA_DMA_RX_THD_VAL_POS)); // Set Clock Mode (CPOL and CPHA). - error = MXC_SPI_SetClkMode((init->spi), (init->mode)); + error = MXC_SPI_SetClkMode((init->spi), (init->clk_mode)); if (error != E_NO_ERROR) { return error; } @@ -1346,7 +1351,7 @@ int MXC_SPI_RevA2_ControllerTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_bu } // 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; @@ -1492,7 +1497,7 @@ int MXC_SPI_RevA2_ControllerTransactionB(mxc_spi_reva_regs_t *spi, uint8_t *tx_b } // Blocking - while (STATES[spi_num].controller_done == false) {} + while (STATES[spi_num].transaction_done == false) {} return E_SUCCESS; } @@ -1522,7 +1527,7 @@ int MXC_SPI_RevA2_ControllerTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx } // Initialize SPIn state to handle DMA transactions. - STATES[spi_num].controller_done = false; + STATES[spi_num].transaction_done = false; STATES[spi_num].tx_buffer = tx_buffer; STATES[spi_num].tx_done = false; @@ -1658,7 +1663,7 @@ int MXC_SPI_RevA2_ControllerTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx // 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; + STATES[spi_num].transaction_done = true; } STATES[spi_num].tx_done = true; @@ -1780,7 +1785,7 @@ int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *t } // Blocking - while (((STATES[spi_num].controller_done == false && STATES[spi_num].tx_done == false) && + while (((STATES[spi_num].transaction_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))) {} @@ -1788,6 +1793,352 @@ int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *t return E_SUCCESS; } +int MXC_SPI_RevA2_TargetTransaction(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) +{ + int spi_num, tx_dummy_fr_len; + + // 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; + } + + // 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].transaction_done = false; + + STATES[spi_num].tx_buffer = tx_buffer; + STATES[spi_num].tx_cnt = 0; + STATES[spi_num].tx_done = false; + + STATES[spi_num].rx_buffer = rx_buffer; + STATES[spi_num].rx_cnt = 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; + } + + // 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; + } + + STATES[spi_num].deassert = deassert; + + // 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) { + // 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; + + // 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->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_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); + } + + // 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); + + if (tx_fr_len > 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_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_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); + + return E_SUCCESS; +} + +int MXC_SPI_RevA2_TargetTransactionDMA(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) +{ + int spi_num, tx_dummy_fr_len; + // For readability purposes. + int rx_ch, tx_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; + } + + // Make sure DMA is initialized. + if (STATES[spi_num].init.use_dma == false || STATES[spi_num].dma_initialized == false) { + return E_BAD_STATE; + } + + // Make sure SPI Instance was initialized. + if (STATES[spi_num].initialized == false) { + return E_BAD_STATE; + } + + // Initialize SPIn state to handle DMA transactions. + STATES[spi_num].transaction_done = false; + + STATES[spi_num].tx_buffer = tx_buffer; + STATES[spi_num].tx_done = false; + + STATES[spi_num].rx_buffer = rx_buffer; + 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; + } + + // 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; + } + + STATES[spi_num].deassert = deassert; + + // 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; + + // 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->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_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); + } + + // 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); + + // 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_fr_len > 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].init.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 byte) 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_fr_len - 1); + + // Set to 3 byte (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_cnt += 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_cnt); + STATES[spi_num].dma->ch[tx_ch].cnt = (STATES[spi_num].tx_len - STATES[spi_num].tx_cnt); + + // Set to 4 byte (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); + } + + 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_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); + } + + // 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].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_fr_len == 0 && STATES[spi_num].init.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_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 + } + + // 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); + + // 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_len; + + // 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].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); + } + + 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); + } + + // Target transaction is ready. + return E_SUCCESS; +} + /* ** Handler Functions ** */ void MXC_SPI_RevA2_Handler(mxc_spi_reva_regs_t *spi) @@ -1825,7 +2176,7 @@ 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 @@ -1893,7 +2244,7 @@ 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; + STATES[spi_num].transaction_done = true; } } @@ -1953,7 +2304,7 @@ 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; + 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 58c3916bce..033ed6d9e2 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h @@ -149,6 +149,14 @@ int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *t uint32_t rx_fr_len, uint8_t deassert, mxc_spi_target_t *target); +int MXC_SPI_RevA2_TargetTransaction(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); + +int MXC_SPI_RevA2_TargetTransactionDMA(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); + /* ** Handler Functions ** */ void MXC_SPI_RevA2_Handler(mxc_spi_reva_regs_t *spi); From 7c4f0d96e4040544e16b477dabb5c8967036aeda Mon Sep 17 00:00:00 2001 From: Sihyung Woo Date: Tue, 11 Jul 2023 15:56:14 -0500 Subject: [PATCH 02/85] feat(Examples): Update SPI_MasterSlave example to use SPI v2 functions for MAX78002 --- Examples/MAX78002/SPI_MasterSlave/README.md | 91 +++++++- Examples/MAX78002/SPI_MasterSlave/main.c | 229 ++++++++++++------- Examples/MAX78002/SPI_MasterSlave/project.mk | 4 - 3 files changed, 228 insertions(+), 96 deletions(-) diff --git a/Examples/MAX78002/SPI_MasterSlave/README.md b/Examples/MAX78002/SPI_MasterSlave/README.md index 25a7737c51..9987002063 100644 --- a/Examples/MAX78002/SPI_MasterSlave/README.md +++ b/Examples/MAX78002/SPI_MasterSlave/README.md @@ -2,15 +2,87 @@ This example demonstrates a SPI transaction between two distinct SPI peripherals on the MAX78002. -SPI1 is setup as the 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. +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 master ends the transaction, the data received by the master and the slave is compared to the data sent by their counterpart to ensure all bytes were received properly. +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. ## Software -### SPI v2 Library +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. -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. +### 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 of initialization 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. ### Project Usage @@ -35,12 +107,13 @@ Universal instructions on building, flashing, and debugging this project can be The Console UART of the device will output these messages: ``` -************************ SPI Master-Slave Example ************************ +************************ SPI Controller-Target Example ************************ This example sends data between two SPI peripherals in the MAX78002. -SPI1 is configured as the slave and SPI0 is configured as the master. -Each SPI peripheral sends 1024 bytes on the SPI bus. If the data received -by each SPI instance matches the data sent by the other instance, the -green LED will illuminate, otherwise the red LED will illuminate. +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. diff --git a/Examples/MAX78002/SPI_MasterSlave/main.c b/Examples/MAX78002/SPI_MasterSlave/main.c index be9d5757e3..6a74b94d17 100644 --- a/Examples/MAX78002/SPI_MasterSlave/main.c +++ b/Examples/MAX78002/SPI_MasterSlave/main.c @@ -52,128 +52,191 @@ #include "spi.h" /***** Definitions *****/ + +#define DMA 0 + #define DATA_LEN 1024 // Words #define DATA_SIZE 8 #define VALUE 0xFF #define SPI_SPEED 100000 // Bit Rate (Max.: 1,850,000) -#define SPI_MASTER MXC_SPI1 -#define SPI_MASTER_SSIDX 0 -#define SPI_SLAVE MXC_SPI0 -#define SPI_SLAVE_SSIDX 0 -#define SPI_SLAVE_IRQ SPI0_IRQn +#define SPI_CONTROLLER MXC_SPI1 +#define SPI_CONTROLLER_TSIDX 0 +#define SPI_CONTROLLER_IRQ SPI1_IRQn +#define SPI_TARGET MXC_SPI0 +#define SPI_TARGET_TSIDX 0 +#define SPI_TARGET_IRQ SPI0_IRQn /***** Globals *****/ -uint8_t master_rx[DATA_LEN]; -uint8_t master_tx[DATA_LEN]; -uint8_t slave_rx[DATA_LEN]; -uint8_t slave_tx[DATA_LEN]; +uint16_t controller_rx[DATA_LEN]; +uint16_t controller_tx[DATA_LEN]; +uint16_t target_rx[DATA_LEN]; +uint16_t target_tx[DATA_LEN]; +uint8_t TX_DMA_CH, RX_DMA_CH; /***** Functions *****/ -void SPI_Slave_IRQHandler(void) +void SPI_Controller_IRQHandler(void) +{ + MXC_SPI_AsyncHandler(SPI_CONTROLLER); +} + +void SPI_Target_IRQHandler(void) +{ + MXC_SPI_AsyncHandler(SPI_TARGET); +} + +#if DMA +void DMA_TX_IRQHandler(void) { - MXC_SPI_AsyncHandler(SPI_SLAVE); + MXC_SPI_DMA_TX_Handler(SPI_TARGET); } +void DMA_RX_IRQHandler(void) +{ + MXC_SPI_DMA_RX_Handler(SPI_TARGET); +} +#endif + int main(void) { - mxc_spi_req_t slave_req; - mxc_spi_req_t master_req; - mxc_spi_pins_t spi_pins; - spi_pins.clock = true; - spi_pins.ss0 = true; - spi_pins.ss1 = false; - spi_pins.ss2 = false; - spi_pins.miso = true; - spi_pins.mosi = true; - spi_pins.sdio2 = false; - spi_pins.sdio3 = false; - spi_pins.vddioh = false; - - printf("\n************************ SPI Master-Slave Example ************************\n"); + int error; + mxc_spi_init_t controller_init; // L. Master + mxc_spi_init_t target_init; // L. Slave + mxc_spi_target_t target; + + 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 slave and SPI%d is configured as the master.\n", - MXC_SPI_GET_IDX(SPI_SLAVE), MXC_SPI_GET_IDX(SPI_MASTER)); - printf("Each SPI peripheral sends 1024 bytes on the SPI bus. If the data received\n", DATA_LEN); - printf("by each SPI instance matches the data sent by the other instance, the\n"); - printf("green LED will illuminate, otherwise the red LED will illuminate.\n\n"); + printf("SPI%d is configured as the target (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"); - printf("Press PB1 to begin transaction.\n\n"); + printf("Press PB1 to begin transaction.\n"); while (!PB_Get(0)) {} /***** Initialize data buffers *****/ for (int i = 0; i < DATA_LEN; i++) { - master_tx[i] = i; - slave_tx[i] = i; + controller_tx[i] = i; + target_tx[i] = i; } - memset(master_rx, 0x0, DATA_LEN * sizeof(uint8_t)); - memset(slave_rx, 0x0, DATA_LEN * sizeof(uint8_t)); - /***** Configure master *****/ - if (MXC_SPI_Init(SPI_MASTER, 1, 0, 1, (1 << SPI_MASTER_SSIDX), SPI_SPEED, spi_pins) != - E_NO_ERROR) { - printf("\nSPI MASTER INITIALIZATION ERROR\n"); + memset(controller_rx, 0x0, DATA_LEN * sizeof(uint8_t)); + memset(target_rx, 0x0, DATA_LEN * sizeof(uint8_t)); + + /***** Configure Controller (L. Master) *****/ + controller_init.spi = SPI_CONTROLLER; + controller_init.freq = SPI_SPEED; + controller_init.spi_pins = NULL; // Use default, predefined pins + controller_init.mode = MXC_SPI_INTERFACE_STANDARD; + controller_init.type = MXC_SPI_TYPE_CONTROLLER; // L. Master + controller_init.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 + controller_init.frame_size = DATA_SIZE; + controller_init.callback = NULL; + controller_init.use_dma = false; + + // 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). + + controller_init.ts_control = + MXC_SPI_TSCONTROL_SW_DRV; // SPI Driver will handle deassertion for TS pins. + controller_init.target.pins = target_pins; + controller_init.target.active_polarity = 0; + controller_init.vssel = MXC_GPIO_VSSEL_VDDIO; // Set SPI pins to VDDIOH (3.3V). + + // Select target for transaction. + target.pins = target_pins; // Custom pins +#else + controller_init.ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // HW will deassert/assert TS pins. + controller_init.target.active_polarity = 0; + controller_init.target.init_mask = 1 << SPI_CONTROLLER_TSIDX; // Initialize Target Select 0 pin. + controller_init.vssel = MXC_GPIO_VSSEL_VDDIO; + + // Select target for transaction. + target.index = SPI_CONTROLLER_TSIDX; +#endif + + error = MXC_SPI_Init_v2(&controller_init); + if (error != E_NO_ERROR) { + printf("\nSPI CONTROLLER INITIALIZATION ERROR\n"); while (1) {} } - MXC_SPI_SetDataSize(SPI_MASTER, DATA_SIZE); - MXC_SPI_SetWidth(SPI_MASTER, SPI_WIDTH_STANDARD); - - /***** Configure slave *****/ - if (MXC_SPI_Init(SPI_SLAVE, 0, 0, 1, (1 << SPI_SLAVE_SSIDX), SPI_SPEED, spi_pins) != - E_NO_ERROR) { - printf("\nSPI SLAVE INITIALIZATION ERROR\n"); + MXC_NVIC_SetVector(SPI_CONTROLLER_IRQ, SPI_Controller_IRQHandler); + NVIC_EnableIRQ(SPI_CONTROLLER_IRQ); + + /***** Configure Target (L. Slave) *****/ + target_init.spi = SPI_TARGET; + target_init.freq = SPI_SPEED; + target_init.spi_pins = NULL; // Use default, predefined pins + target_init.mode = MXC_SPI_INTERFACE_STANDARD; + target_init.type = MXC_SPI_TYPE_TARGET; // L. Slave + target_init.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 + target_init.frame_size = DATA_SIZE; + target_init.callback = NULL; + target_init.ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // Target transactions only supports HW_AUTO mode + target_init.target.active_polarity = 0; + target_init.target.init_mask = 1 << SPI_TARGET_TSIDX; // Initialize Target Select 0 pin. + target_init.vssel = MXC_GPIO_VSSEL_VDDIO; + +#if DMA + target_init.use_dma = true; + target_init.dma = MXC_DMA; +#else + target_init.use_dma = false; +#endif + + error = MXC_SPI_Init_v2(&target_init); + if (error != E_NO_ERROR) { + printf("\nSPI TARGET INITIALIZATION ERROR\n"); while (1) {} } - MXC_SPI_SetDataSize(SPI_SLAVE, DATA_SIZE); - MXC_SPI_SetWidth(SPI_SLAVE, SPI_WIDTH_STANDARD); - - MXC_NVIC_SetVector(SPI_SLAVE_IRQ, SPI_Slave_IRQHandler); - NVIC_EnableIRQ(SPI_SLAVE_IRQ); - - /***** Initialize Transaction Parameters *****/ - master_req.spi = SPI_MASTER; - master_req.txData = (uint8_t *)master_tx; - master_req.rxData = (uint8_t *)master_rx; - master_req.txLen = DATA_LEN; - master_req.rxLen = DATA_LEN; - master_req.ssIdx = SPI_MASTER_SSIDX; - master_req.ssDeassert = 1; - master_req.txCnt = 0; - master_req.rxCnt = 0; - master_req.completeCB = NULL; - - slave_req.spi = SPI_SLAVE; - slave_req.txData = (uint8_t *)slave_tx; - slave_req.rxData = (uint8_t *)slave_rx; - slave_req.txLen = DATA_LEN; - slave_req.rxLen = DATA_LEN; - slave_req.ssIdx = SPI_SLAVE_SSIDX; - slave_req.ssDeassert = 1; - slave_req.txCnt = 0; - slave_req.rxCnt = 0; - slave_req.completeCB = NULL; +#if 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 /***** Perform Transaction *****/ - MXC_SPI_SlaveTransactionAsync(&slave_req); - MXC_SPI_MasterTransaction(&master_req); +#if DMA + MXC_SPI_TargetTransactionDMA(SPI_TARGET, target_tx, DATA_LEN, target_rx, DATA_LEN, 1); +#else + MXC_SPI_TargetTransaction(SPI_TARGET, target_tx, DATA_LEN, target_rx, DATA_LEN, 1); +#endif + + MXC_SPI_ControllerTransactionB(SPI_CONTROLLER, controller_tx, DATA_LEN, controller_rx, DATA_LEN, 1, &target); /***** Verify Results *****/ - if (memcmp(slave_rx, master_tx, sizeof(master_tx)) != 0) { // Master->Slave - printf("\nSlave failed to receive data.\n"); + 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(master_rx, slave_tx, sizeof(slave_tx)) != 0) { // Slave->Master - printf("\nMaster failed to receive data.\n"); + } 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_MASTER); - MXC_SPI_Shutdown(SPI_SLAVE); + MXC_SPI_Shutdown(SPI_CONTROLLER); + MXC_SPI_Shutdown(SPI_TARGET); - LED_On(0); // indicates SUCCESS + LED_On(0); // Indicates SUCCESS printf("\nExample Succeeded\n"); return E_NO_ERROR; } diff --git a/Examples/MAX78002/SPI_MasterSlave/project.mk b/Examples/MAX78002/SPI_MasterSlave/project.mk index b4897bd585..f068448db8 100644 --- a/Examples/MAX78002/SPI_MasterSlave/project.mk +++ b/Examples/MAX78002/SPI_MasterSlave/project.mk @@ -8,7 +8,3 @@ # ********************************************************** # 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 From 3bf04919ec78c66349c96021f8efd46cc831f7ae Mon Sep 17 00:00:00 2001 From: Sihyung Woo Date: Tue, 11 Jul 2023 15:57:17 -0500 Subject: [PATCH 03/85] fix(Examples): Update SPI README for MAX78002 --- Examples/MAX78002/SPI/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/MAX78002/SPI/README.md b/Examples/MAX78002/SPI/README.md index 7f6f63d867..79826fa78a 100644 --- a/Examples/MAX78002/SPI/README.md +++ b/Examples/MAX78002/SPI/README.md @@ -23,11 +23,11 @@ The SPI v2 Library is backwards compatible with the previous SPI API - meaning t 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. +Use the `MXC_SPI_Init_v2(...)` function for 1) to decrease overhead of initialization 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_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) From c499001c946f41b3644854955acb6fbd4a294589 Mon Sep 17 00:00:00 2001 From: sihyung-maxim Date: Tue, 11 Jul 2023 21:04:09 +0000 Subject: [PATCH 04/85] clang-format bot reformatting. --- Examples/MAX78002/SPI_MasterSlave/main.c | 9 ++++++--- .../PeriphDrivers/Include/MAX78002/spi.h | 10 ++++------ .../PeriphDrivers/Source/SPI/spi_ai87_v2.c | 19 +++++++++++-------- .../PeriphDrivers/Source/SPI/spi_reva2.c | 19 ++++++++++--------- .../PeriphDrivers/Source/SPI/spi_reva2.h | 8 ++++---- 5 files changed, 35 insertions(+), 30 deletions(-) diff --git a/Examples/MAX78002/SPI_MasterSlave/main.c b/Examples/MAX78002/SPI_MasterSlave/main.c index 6a74b94d17..5b7c2c7a09 100644 --- a/Examples/MAX78002/SPI_MasterSlave/main.c +++ b/Examples/MAX78002/SPI_MasterSlave/main.c @@ -106,7 +106,8 @@ int main(void) 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 target (L. Slave) and SPI%d is configured\n", MXC_SPI_GET_IDX(SPI_TARGET), MXC_SPI_GET_IDX(SPI_CONTROLLER)); + printf("SPI%d is configured as the target (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"); @@ -181,7 +182,8 @@ int main(void) target_init.clk_mode = MXC_SPI_CLKMODE_0; // CPOL: 0, CPHA: 0 target_init.frame_size = DATA_SIZE; target_init.callback = NULL; - target_init.ts_control = MXC_SPI_TSCONTROL_HW_AUTO; // Target transactions only supports HW_AUTO mode + target_init.ts_control = + MXC_SPI_TSCONTROL_HW_AUTO; // Target transactions only supports HW_AUTO mode target_init.target.active_polarity = 0; target_init.target.init_mask = 1 << SPI_TARGET_TSIDX; // Initialize Target Select 0 pin. target_init.vssel = MXC_GPIO_VSSEL_VDDIO; @@ -220,7 +222,8 @@ int main(void) MXC_SPI_TargetTransaction(SPI_TARGET, target_tx, DATA_LEN, target_rx, DATA_LEN, 1); #endif - MXC_SPI_ControllerTransactionB(SPI_CONTROLLER, controller_tx, DATA_LEN, controller_rx, DATA_LEN, 1, &target); + MXC_SPI_ControllerTransactionB(SPI_CONTROLLER, controller_tx, DATA_LEN, controller_rx, DATA_LEN, + 1, &target); /***** Verify Results *****/ if (memcmp(target_rx, controller_tx, sizeof(controller_tx)) != 0) { // Controller->Target diff --git a/Libraries/PeriphDrivers/Include/MAX78002/spi.h b/Libraries/PeriphDrivers/Include/MAX78002/spi.h index 41069c2546..bcc7b7daa4 100644 --- a/Libraries/PeriphDrivers/Include/MAX78002/spi.h +++ b/Libraries/PeriphDrivers/Include/MAX78002/spi.h @@ -1051,9 +1051,8 @@ int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req); * * @return See \ref MXC_Error_Codes for the list of error return codes. */ -int MXC_SPI_TargetTransaction(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); +int MXC_SPI_TargetTransaction(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); /** * @brief Setup a DMA driven SPI Target transaction. @@ -1067,9 +1066,8 @@ int MXC_SPI_TargetTransaction(mxc_spi_regs_t *spi, uint8_t *tx_buffer, * * @return See \ref MXC_Error_Codes for the list of error return codes. */ -int MXC_SPI_TargetTransactionDMA(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); +int MXC_SPI_TargetTransactionDMA(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); /* ** Handler Functions ** */ diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c b/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c index 0d99cf6719..d6719c39cb 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_ai87_v2.c @@ -774,8 +774,8 @@ int MXC_SPI_MasterTransactionAsync(mxc_spi_req_t *req) } 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); + req->tx_len, req->rx_buffer, req->rx_len, + req->deassert, &target); } int MXC_SPI_MasterTransactionDMA(mxc_spi_req_t *req) @@ -873,7 +873,8 @@ int MXC_SPI_SlaveTransactionAsync(mxc_spi_req_t *req) return error; } - return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, req->tx_len, req->rx_buffer, req->rx_len, req->deassert); + return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, + req->tx_len, req->rx_buffer, req->rx_len, req->deassert); } int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req) @@ -902,18 +903,20 @@ int MXC_SPI_SlaveTransactionDMA(mxc_spi_req_t *req) return error; } - return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, req->tx_len, req->rx_buffer, req->rx_len, req->deassert); + return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)(req->spi), req->tx_buffer, + req->tx_len, req->rx_buffer, req->rx_len, + req->deassert); } int MXC_SPI_TargetTransaction(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) + uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert) { return MXC_SPI_RevA2_TargetTransaction((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, - rx_buffer, rx_fr_len, deassert); + rx_buffer, rx_fr_len, deassert); } int MXC_SPI_TargetTransactionDMA(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) + uint8_t *rx_buffer, uint32_t rx_fr_len, uint8_t deassert) { int error; @@ -923,7 +926,7 @@ int MXC_SPI_TargetTransactionDMA(mxc_spi_regs_t *spi, uint8_t *tx_buffer, uint32 } return MXC_SPI_RevA2_TargetTransactionDMA((mxc_spi_reva_regs_t *)spi, tx_buffer, tx_fr_len, - rx_buffer, rx_fr_len, deassert); + rx_buffer, rx_fr_len, deassert); } /* ** Handler Functions ** */ diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c index 71485c39bf..c8e9d323ef 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.c @@ -395,8 +395,8 @@ int MXC_SPI_RevA2_Init(mxc_spi_init_t *init) } 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)); + ((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. @@ -1794,8 +1794,8 @@ int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *t } int MXC_SPI_RevA2_TargetTransaction(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) + uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, + uint8_t deassert) { int spi_num, tx_dummy_fr_len; @@ -1904,8 +1904,8 @@ int MXC_SPI_RevA2_TargetTransaction(mxc_spi_reva_regs_t *spi, uint8_t *tx_buffer } int MXC_SPI_RevA2_TargetTransactionDMA(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) + uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, + uint8_t deassert) { int spi_num, tx_dummy_fr_len; // For readability purposes. @@ -2027,8 +2027,8 @@ int MXC_SPI_RevA2_TargetTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buf // 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), 2); + STATES[spi_num].tx_cnt += + 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. @@ -2104,7 +2104,8 @@ int MXC_SPI_RevA2_TargetTransactionDMA(mxc_spi_reva_regs_t *spi, uint8_t *tx_buf 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)); + 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_len; diff --git a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h index 033ed6d9e2..727b86fdfa 100644 --- a/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h +++ b/Libraries/PeriphDrivers/Source/SPI/spi_reva2.h @@ -150,12 +150,12 @@ int MXC_SPI_RevA2_ControllerTransactionDMAB(mxc_spi_reva_regs_t *spi, uint8_t *t mxc_spi_target_t *target); int MXC_SPI_RevA2_TargetTransaction(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); + uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, + uint8_t deassert); int MXC_SPI_RevA2_TargetTransactionDMA(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); + uint32_t tx_fr_len, uint8_t *rx_buffer, uint32_t rx_fr_len, + uint8_t deassert); /* ** Handler Functions ** */ From 4a952f3ed4f4de676a01b727d8d43582c8aa760e Mon Sep 17 00:00:00 2001 From: Sihyung Woo Date: Tue, 11 Jul 2023 16:18:08 -0500 Subject: [PATCH 05/85] feat(Examples): Rename SPI_MasterSlave example to SPI_ControllerTarget for MAX78002: --- Examples/MAX78002/SPI/README.md | 2 +- .../.cproject | 13 +++---------- .../.project | 2 +- .../.settings/language.settings.xml | 4 ++-- .../.settings/org.eclipse.cdt.codan.core.prefs | 0 .../.settings/org.eclipse.cdt.core.prefs | 2 +- .../.settings/org.eclipse.core.resources.prefs | 2 ++ .../.vscode/README.md | 0 .../.vscode/c_cpp_properties.json | 0 .../.vscode/flash.gdb | 0 .../.vscode/launch.json | 0 .../.vscode/settings.json | 7 ++----- .../.vscode/tasks.json | 0 .../Makefile | 0 .../README.md | 4 ++-- .../SPI_ControllerTarget.launch} | 8 ++++---- .../main.c | 13 ++++++------- .../project.mk | 5 +++++ 18 files changed, 29 insertions(+), 33 deletions(-) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.cproject (88%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.project (95%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.settings/language.settings.xml (74%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.settings/org.eclipse.cdt.codan.core.prefs (100%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.settings/org.eclipse.cdt.core.prefs (96%) create mode 100644 Examples/MAX78002/SPI_ControllerTarget/.settings/org.eclipse.core.resources.prefs rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.vscode/README.md (100%) mode change 100755 => 100644 rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.vscode/c_cpp_properties.json (100%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.vscode/flash.gdb (100%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.vscode/launch.json (100%) mode change 100755 => 100644 rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.vscode/settings.json (93%) mode change 100755 => 100644 rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/.vscode/tasks.json (100%) mode change 100755 => 100644 rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/Makefile (100%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/README.md (93%) rename Examples/MAX78002/{SPI_MasterSlave/SPI_MasterSlave.launch => SPI_ControllerTarget/SPI_ControllerTarget.launch} (96%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/main.c (98%) rename Examples/MAX78002/{SPI_MasterSlave => SPI_ControllerTarget}/project.mk (76%) diff --git a/Examples/MAX78002/SPI/README.md b/Examples/MAX78002/SPI/README.md index 79826fa78a..253b4e21fd 100644 --- a/Examples/MAX78002/SPI/README.md +++ b/Examples/MAX78002/SPI/README.md @@ -15,7 +15,7 @@ This example uses the SPI v2 Library. To use the previous SPI library, set `MXC_ ### 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. +The SPI v2 Library still supports the previous SPI API - meaning the previously existing function prototypes have not changed. However, there are functional differences with the interrupt handling for both SPI DMA and blocking SPI transactions that must be updated when porting a project from using the previous SPI API to SPI v2. #### SPI v2 API Differences diff --git a/Examples/MAX78002/SPI_MasterSlave/.cproject b/Examples/MAX78002/SPI_ControllerTarget/.cproject similarity index 88% rename from Examples/MAX78002/SPI_MasterSlave/.cproject rename to Examples/MAX78002/SPI_ControllerTarget/.cproject index 7ff7dc8bed..6d11c43265 100644 --- a/Examples/MAX78002/SPI_MasterSlave/.cproject +++ b/Examples/MAX78002/SPI_ControllerTarget/.cproject @@ -32,14 +32,7 @@ - - - - - - - - +