Part Number: BEAGLEBK
I'm using AM3358 - PRU1 to set up SPI1, and the data goes out D1 (MOSI) and appears at D0 (MISO), but all I ever read from RX0 is 0. I've looked at the very similar threads from bwilcutt and others, but they don't seem to end with an answer. I'm using CCS7.4.0.00015 on WIn10, with XDS110 debug probe.
SPI1 sends 8 words x 32-bits, every 125 us. It looks like this:
The SPI decoder decodes this as below, which is what I expect.
The pin mux is set up in the device tree. Pins 100-103 are SCLK, D0, D1, and CS. D0 is MISO and D1 is MOSI. I think I only need 0x0b at 44e10998, but I was experimenting to get this working. AFAIK there is no Linux driver loaded for SPI.
cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pins
<snip>
pin 100 (PIN100) 44e10990 0000000b pinctrl-single
pin 101 (PIN101) 44e10994 0000002b pinctrl-single
pin 102 (PIN102) 44e10998 0000002b pinctrl-single
pin 103 (PIN103) 44e1099c 0000000b pinctrl-single
<snip>
After running the code below for a few seconds and then pausing the debugger, these are the results. The code initializes the IEP (for 125 us timing generation) and SPI1 (for data transfer). Then it waits in a loop for the timing comparison from the IEP. 8 words are written to the SPI Tx, and 8 words are collected back. Flag status before and after reading RX0 are saved, as well as the RX0 value. The SPI registers are fetched periodically (dbg_spi1_*) for debug reporting. Note that the rxBuf results are all 0.
/** * main.c */ /******************************************************************************* * Included files ******************************************************************************/ /* From Standard C */ #include <stdint.h> /* From PRU Software Support Package */ #include <pru_cfg.h> #include <pru_intc.h> #include <sys_mcspi.h> #include <hw_mcspi.h> /* From AM335X_StarterWare */ #include <soc_AM335X.h> #include <hw_cm_per.h> /* From this project */ #include "pru_iep.h" /* Updated to include all registers from TRM */ /******************************************************************************* * Definitions ******************************************************************************/ #define IEP_CLK 200000000 #define DELAY500NS ( 500 * (IEP_CLK / 1000000) / 1000 ) #define FSYNC_CLK 4000 #define FSYNC_OFFSET 100 / 125 /* FSync at 100 us after CMP0 (~SPI start) */ #define NUM_LINES 16 #define FRAME_COUNT 80 /* Number of frames per Bch buffer, and per uC interrupt */ /* Macros to get individual fields in and out of bitfields. * In general, bits are set to flag an error condition, so single-bit fields * may be set and tested using the field's name directly. */ #define SETFIELD(field, value) (field & ((field##_##value) << field##_SHIFT)) #define SETFIELDVAL(field, value) (field & ((value) << field##_SHIFT)) #define GETFIELD(var, field) ((field & (var)) >> field##_SHIFT) #define MCSPI_CH0CONF_CLKD_CLK_DIV (14) /* 48 / (14 + 1) = 3.2 Mbps = 2.5 us/byte */ #define MCSPI_CH0CTRL_EXTCLK_DIV_EXT (MCSPI_CH0CONF_CLKD_CLK_DIV >> 4) #define SPI_RESET_TIMEOUT (1000) /* Number of times to check if reset is done */ #define CH0CONF_BASE \ SETFIELD(MCSPI_CH0CONF_CLKD, CLK_DIV) \ | SETFIELD(MCSPI_CH0CONF_CLKG, ONECYCLE) \ | SETFIELD(MCSPI_CH0CONF_DMAR, DISABLED) \ | SETFIELD(MCSPI_CH0CONF_DMAW, DISABLED) \ | SETFIELD(MCSPI_CH0CONF_DPE0, DISABLED) \ | SETFIELD(MCSPI_CH0CONF_DPE1, ENABLED) \ | SETFIELD(MCSPI_CH0CONF_EPOL, ACTIVELOW) \ | SETFIELD(MCSPI_CH0CONF_FFER, FFDISABLED) /* 32 byte Rx FIFO */ /* todo was enabled FFENABLED */ \ | SETFIELD(MCSPI_CH0CONF_FFEW, FFENABLED) /* 32 byte Tx FIFO */ \ | SETFIELD(MCSPI_CH0CONF_IS, LINE0) \ | SETFIELD(MCSPI_CH0CONF_PHA, EVEN) /* Set SPI mode polarity 0 phase 1 */ \ | SETFIELD(MCSPI_CH0CONF_POL, ACTIVEHIGH) \ | SETFIELD(MCSPI_CH0CONF_SBE, DISABLED) \ | SETFIELD(MCSPI_CH0CONF_SBPOL, LOWLEVEL) \ | SETFIELD(MCSPI_CH0CONF_SPIENSLV, SPIEN0) \ | SETFIELD(MCSPI_CH0CONF_TCS0, 0P5) \ | SETFIELD(MCSPI_CH0CONF_TRM, TXRX) \ | SETFIELD(MCSPI_CH0CONF_TURBO, ENABLED) \ | SETFIELD(MCSPI_CH0CONF_WL, 32BITS) /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ void init_iep() { CT_IEP.TMR_GLB_CFG = CNT_EN(0); /* Disable counter */ CT_IEP.TMR_GLB_STS = CT_IEP.TMR_GLB_STS; /* Clear global status */ CT_IEP.TMR_CMP0 = IEP_CLK / FSYNC_CLK / 2 - 1; /* TMR_CMP1 comparison must be false when SYNC0 is enabled for * the rising edge of SYNC0 to trigger the output * edge, as opposed to when SYNC0 is enabled. Allow 1 cycle from * CMP1 to SYNC0, and another for SYNC0 to DATA_OUT change. */ CT_IEP.TMR_CMP1 = IEP_CLK / FSYNC_CLK * FSYNC_OFFSET / 2; CT_IEP.TMR_CMP_CFG = CMP_EN0(1) | CMP_EN1(1) | CMP0_RST_CNT_EN(1); CT_IEP.SYNC_START = 0; CT_IEP.DIGIO_DATA_OUT_EN = 0; /* Clear to enable all PR1_EDIO_DATA_OUT */ CT_IEP.DIGIO_CTRL = BIDI_MODE(1) | OUT_MODE(2); /* Update on SYNC0 events */ CT_IEP.TMR_GLB_CFG = CMP_INC(1) | DEFAULT_INC(1) | CNT_EN(1); /* Enable counter */ } void init_SPI(void) { uint32_t i; do { CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; /* Enable OCP master port*/ *(uint8_t *)(SOC_CM_PER_REGS + CM_PER_SPI1_CLKCTRL) |= CM_PER_SPI1_CLKCTRL_MODULEMODE_ENABLE; /* Enable SPI1 module clock */ CT_MCSPI1.SYSCONFIG = SETFIELD(MCSPI_SYSCONFIG_AUTOIDLE, DISABLE) | SETFIELD(MCSPI_SYSCONFIG_CLOCKACTIVITY, BOTH) | SETFIELD(MCSPI_SYSCONFIG_SIDLEMODE, NOIDLE) | SETFIELD(MCSPI_SYSCONFIG_SOFTRESET, INITIATE); for (i = SPI_RESET_TIMEOUT; i && !CT_MCSPI1.SYSSTATUS_bit.RESETDONE; --i) __delay_cycles(200); } while (!i); /* Re-initiate module reset if it failed with timeout */ CT_MCSPI1.MODULCTRL = SETFIELD(MCSPI_MODULCTRL_FDAA, NOSHADOWREG) | SETFIELD(MCSPI_MODULCTRL_INITDLY, NODELAY) | SETFIELD(MCSPI_MODULCTRL_MOA, DISABLED) | SETFIELD(MCSPI_MODULCTRL_MS, MASTER) | SETFIELD(MCSPI_MODULCTRL_PIN34, 4PINMODE) | SETFIELD(MCSPI_MODULCTRL_SINGLE, SINGLE) | SETFIELD(MCSPI_MODULCTRL_SYSTEM_TEST, OFF); CT_MCSPI1.CH0CONF = CH0CONF_BASE | SETFIELD(MCSPI_CH0CONF_FORCE, DEASSERT); /* CS inactive */ CT_MCSPI1.CH0CTRL = SETFIELD(MCSPI_CH0CTRL_EXTCLK, DIV_EXT) | SETFIELD(MCSPI_CH0CTRL_EN, ACTIVE); CT_MCSPI1.CH1CTRL = CT_MCSPI1.CH2CTRL = CT_MCSPI1.CH3CTRL = SETFIELD(MCSPI_CH1CTRL_EN, INACTIVE); } /* * main.c */ int main(void) { uint32_t rxBuf[8]; // todo remove uint32_t statBeforeBuf[8]; // todo remove uint32_t statAfterBuf[8]; // todo remove uint32_t dbg_spi1_SYSCONFIG; uint32_t dbg_spi1_SYSSTATUS; uint32_t dbg_spi1_MODULCTRL; uint32_t dbg_spi1_CH0CONF; uint32_t dbg_spi1_CH0CTRL; uint8_t g_frameCount = 0; uint32_t FSync = 0; uint32_t tmp; int8_t i; init_SPI(); init_iep(); while (1) { if (CMP_HIT0(1) & (tmp = CT_IEP.TMR_CMP_STS)) { /* Wait for CMP0 to reset count */ CT_IEP.TMR_CMP_STS = tmp; /* Clear comparator flags */ CT_IEP.DIGIO_DATA_OUT = FSync = ~FSync; /* Toggle FSync value and update next DIGIO data */ CT_IEP.SYNC_CTRL = SYNC_EN(0) | SYNC0_EN(0); /* Disable and ... */ CT_IEP.SYNC_CTRL = SYNC_EN(1) | SYNC0_EN(1); /* re-enable to prime SYNC0 one-shot */ CT_MCSPI1.CH0CONF = CH0CONF_BASE | SETFIELD(MCSPI_CH0CONF_FORCE, ASSERT); /* CS active */ CT_MCSPI1.CH0CTRL = SETFIELD(MCSPI_CH0CTRL_EXTCLK, DIV_EXT) | SETFIELD(MCSPI_CH0CTRL_EN, ACTIVE); for (i = NUM_LINES - 1; i >= 0; i-=2){ while (!CT_MCSPI1.CH0STAT_bit.TXS) __delay_cycles(DELAY500NS); /* Check for Tx reg empty */ CT_MCSPI1.TX0 = 0x09000b00 | (i << 28) | ((i - 1) << 12); } for (i = NUM_LINES - 1; i >= 0; i-=2){ while (!CT_MCSPI1.CH0STAT_bit.RXS) { __delay_cycles(DELAY500NS); /* Loop waiting for Rx reg full */ } statBeforeBuf[i/2] = CT_MCSPI1.CH0STAT; rxBuf[i/2] = CT_MCSPI1.RX0; statAfterBuf[i/2] = CT_MCSPI1.CH0STAT; } CT_MCSPI1.CH0CTRL = SETFIELD(MCSPI_CH0CTRL_EXTCLK, DIV_EXT) | SETFIELD(MCSPI_CH0CTRL_EN, INACTIVE); CT_MCSPI1.CH0CONF = CH0CONF_BASE | SETFIELD(MCSPI_CH0CONF_FORCE, DEASSERT); /* CS inactive */ if (g_frameCount < FRAME_COUNT) { g_frameCount++; } else { g_frameCount = 0; dbg_spi1_SYSCONFIG = CT_MCSPI1.SYSCONFIG; dbg_spi1_SYSSTATUS = CT_MCSPI1.SYSSTATUS; dbg_spi1_MODULCTRL = CT_MCSPI1.MODULCTRL; dbg_spi1_CH0CONF = CT_MCSPI1.CH0CONF; dbg_spi1_CH0CTRL = CT_MCSPI1.CH0CTRL; } } } /* Should never return */ return 1; }
Thanks,
Steve.