Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(PeriphDrivers)!: Add SPI v2 Implementation to MAX78002 #632

Merged
merged 124 commits into from
Jun 26, 2023
Merged

Conversation

sihyung-maxim
Copy link
Contributor

@sihyung-maxim sihyung-maxim commented Jun 20, 2023

The transaction functions look long, but that's because there are register fields explicitly set (even to 0) and there are more checks in place, whereas the previous implementation got away with assuming certain register fields are 0 after a reset and never cleared any fields.

Ready for review!

Average estimate times from start of transaction function call to start of transaction:
On default ISO.

SPI v2
~43us non-DMA
~26us DMA

Previous SPI
~60us non-DMA
~142us DMA

Jake-Carter and others added 30 commits February 21, 2023 13:22
- Working standard reads/writes
- Working QSPI reads/writes
- If the value of the dummy byte was defined locally inside of the
  spi_transmit function, it would introduce some glitches on the SPI
  MOSI line.  Suspected compiler optimization issue.

  For some reason, these glitches also corrupted the MISO line.  This
  caused RX data to be corrupted, and ram reads would return incorrect
  values.
- `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` //<==
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No description for target


int MXC_SPI_InitStruct(mxc_spi_init_t *init)
{
return MXC_SPI_InitStruct(init);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MXC_SPI_RevA2_InitStruct & MXC_SPI_RevA2InitStructDMA?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was updated while you were reviewing.


#ifdef MXC_SPI0
} else if (spi == MXC_SPI0) {
if (index > MXC_SPI1_TS_INSTANCES) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MXC_SPI0_TS_INSTANCES


if (req->tx_buffer != NULL) {
switch (spi_num) {
case 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason SPI1 goes with index 0 and SPI0 goes with index 1 here? Same question for rx_reqsel?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is prevalent in the ME17, ME18, AI85, and AI87. Originally, I believe this numbering flip was made to support the previous design where the AHB SPI had a lower instance number than the APB SPI, which caused problems with the RISCV seeing incorrect SPI instances (RISCV only sees the APB SPI). We usually order our SPI instances with APB SPI instances first (lower instance numbers) and AHB instances second (higher instance numbers).

The SPI instance ordering might have been updated with later designs, but the current instance numbering was kept since it is a breaking change.


target.index = req->ssIdx;

error = MXC_SPI_SetRegisterCallback(req->spi, req->callback, req->callback_data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetRegisterCallback is odd. I'd suggest choosing one verb or the other: SetCallback or RegisterCallback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced with SetCallback

}
}

int MXC_SPI_ReadyForSleep(mxc_spi_reva_regs_t *spi)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Any reason these aren't supported going forward?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it's implemented now.

if (STATES[spi_num].tx_buffer && STATES[spi_num].tx_len > 0) {
// Write to the FIFO for byte size transactions (message sizes for 8 bits or less)
if (STATES[spi_num].init.frame_size <= 8) {
while (((spi->dma & MXC_F_SPI_REVA_DMA_TX_LVL) >> MXC_F_SPI_REVA_DMA_TX_LVL_POS) <
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we exit this loop if tx_len == tx_cnt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop condition checks whether there is available space in the transmit FIFO before writing to the transmit FIFO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrote this later, but note, the transaction (mainly for message lengths greater than SPI FIFO depth), doesn't spend its entire time in a single interrupt. Multiple interrupts to write/read the FIFO are triggered, depending on the status of the FIFO. Doing tx_len == tx_cnt for long transactions causes the CPU to spend its entire time in a single interrupt handler even if the FIFO is not ready.


remain = STATES[spi_num].tx_len - STATES[spi_num].tx_cnt;

if (remain) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason the threshold is only updated for halfword size transactions? Same for RX threshold below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For byte size frames, it's as simple as writing a byte to the TX FIFO. Unfortunately, transmitting halfword size frames is not as straightforward. Halfword-size frames require extra care on how it's packaged during the transaction. The remaining number of frames (if less than FIFO depth) needs to match the threshold value for the hardware to properly send the remaining frames or the transaction might not end.

if (STATES[spi_num].rx_buffer && STATES[spi_num].rx_len > 0) {
// Read the FIFO for byte size transactions (message sizes for 8 bits or less)
if (STATES[spi_num].init.frame_size <= 8) {
while ((spi->dma & MXC_F_SPI_REVA_DMA_RX_LVL)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exit loop if rx_cnt == rx_len?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Register level is more reliable than system level checks. Note, the transaction (mainly for message lengths greater than SPI FIFO depth), doesn't spend its entire time in a single interrupt. Multiple interrupts to write/read the FIFO are triggered, depending on the status of the FIFO.

}
}

spi->dma = 2151718466;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic number?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, need to delete that.

@sihyung-maxim
Copy link
Contributor Author

/clang-format-run

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new naming convention, is it clear that the non-blocking functions are "async" and the AsyncHandler needs to be called when using these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a note in the header file. Do you think the "Async" name should be added to these controller functions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial gut reaction was "yes". Transaction, TransactionAsync, and TransactionDMA all make sense to me. TransactionDMAAsync, not so much.

* This function initializes everything necessary to call a SPI transaction function.
* Some parameters are set to defaults as follows:
* SPI Mode - 0
* SPI Width - SPI_WIDTH_STANDARD (even if quadModeUsed is set)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are SPI mode and width forced here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not, just a copy-paste error.

union {
int deassert;
int ssDeassert; // ssDeassert - deprecated name
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this with a union is cool. Good approach for the future

* txData begin to recieve data, padding MOSI with DefaultTXData
*
*
* @deprecated.
Copy link
Contributor

@Jake-Carter Jake-Carter Jun 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is mxc_spi_width_t deprecated? I don't immediately see the necessity for renaming the struct and functions to mxc_spi_interface_t equivalents. Seems like they do exactly the same thing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They do, but it doesn't follow the naming convention in the types (lack of MXC_ prefix). The mxc_spi_width_t is not the best name to use for the interface mode because it can be confused with the message/frame widths. It's also not a common term used to select the interface mode in other peripheral libraries from other vendors (I've only seen ours use it).

This reason is similar to why I added mxc_spi_clkmode_t to replace mxc_spi_mode_t in SPI v2. The term "mode" has been thrown around a lot and, although it refers to the clock mode, it's been used to represent either "master/slave mode", "clock mode", or the interface mode (dual mode, quad mode, 3-wire mode, and 4-wire mode).

I just want to make the terminology clearer.

@sihyung-maxim
Copy link
Contributor Author

/clang-format-run

@sihyung-maxim
Copy link
Contributor Author

/clang-format-run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
MAX32520 Related to the MAX32520 (ES17) MAX32570 Related to the MAX32570 (ME13) MAX32650 Related to the MAX32650 (ME10) MAX32655 Related to the MAX32655 (ME17) MAX32660 Related to the MAX32660 (ME11) MAX32662 Related to the MAX32662 (ME12) MAX32665 Related to the MAX32665 (ME14) MAX32670 Related to the MAX32670 (ME15) MAX32672 Related to the MAX32672 (ME21) MAX32675 Related to the MAX32675 (ME16) MAX32680 Related to the MAX32680 (ME20) MAX32690 Related to the MAX32690 (ME18) MAX78000 Related to the MAX78000 (AI85) MAX78002 Related to the MAX78002 (AI87) Ready for review Raise "Ready" flag if PR is ready for review after WIP is down.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants