Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cores/spi: Add new SPIMMAP core allowing doing SPI accesses directly …
…from MMAP. Implements a new SPIMMAP module, allowing accessing multiple SPI peripherals directly from MMAP. It allows configurable SPI transactions: mode, bit order, and data width. Developed and funded through a collaboration with MoTeC. Example of integration: # SPI MMAP --------------------------------------------------------------------------------- spi_pads = Record([("clk", 1), ("cs_n", 8), ("mosi", 1), ("miso", 1)]) spi_mmap_tx_region = SoCRegion(origin=0x8000_0000, size=4096, cached=False) spi_mmap_rx_region = SoCRegion(origin=0x8000_1000, size=4096, cached=False) self.spi_mmap = SPIMMAP( pads = spi_pads, data_width = 32, sys_clk_freq = sys_clk_freq, tx_origin = spi_mmap_tx_region.origin, rx_origin = spi_mmap_rx_region.origin, tx_fifo_depth = 32, rx_fifo_depth = 32, ) self.bus.add_slave(name="spi_tx", slave = self.spi_mmap.tx_mmap.bus, region = spi_mmap_tx_region, ) self.bus.add_slave(name="spi_rx", slave = self.spi_mmap.rx_mmap.bus, region = spi_mmap_rx_region, ) self.irq.add("spi_mmap", use_loc_if_exists=True) Example of use from CPU C firmware: /* SPI TX Offsets */ #define SPI_TX_CTRL_ENABLE (1 << 0) #define SPI_TX_CTRL_THRESHOLD (1 << 16) #define SPI_TX_STAT_ONGOING (1 << 0) #define SPI_TX_STAT_EMPTY (1 << 1) #define SPI_TX_STAT_FULL (1 << 2) #define SPI_TX_STAT_LEVEL (1 << 16) /* SPI RX Offsets */ #define SPI_RX_CTRL_ENABLE (1 << 0) #define SPI_RX_CTRL_THRESHOLD (1 << 16) #define SPI_RX_STAT_ONGOING (1 << 0) #define SPI_RX_STAT_EMPTY (1 << 1) #define SPI_RX_STAT_FULL (1 << 2) #define SPI_RX_STAT_LEVEL (1 << 16) /* SPI TX/RX Engine */ #define SPI_TX_RX_ENGINE_ENABLE (1 << 0) /* SPI SLOT Offsets */ #define SPI_SLOT_ENABLE (1 << 0) #define SPI_SLOT_MODE (1 << 1) #define SPI_SLOT_LENGTH (1 << 3) #define SPI_SLOT_BITORDER (1 << 5) #define SPI_SLOT_LOOPBACK (1 << 6) #define SPI_SLOT_DIVIDER (1 << 16) /* SPI SLOT Values */ #define SPI_SLOT_MODE_0 0b00 #define SPI_SLOT_MODE_3 0b11 #define SPI_SLOT_LENGTH_32B 0b00 #define SPI_SLOT_LENGTH_16B 0b01 #define SPI_SLOT_LENGTH_8B 0b10 #define SPI_SLOT_BITORDER_MSB_FIRST 0b0 #define SPI_SLOT_BITORDER_LSB_FIRST 0b1 #define SPI_SLOT_EV_TX (1 << 0) #define SPI_SLOT_EV_RX (1 << 1) /* Test SPI with various length (BE) */ void test_spi_length_8_16_32(void) { volatile unsigned char *spi_tx_8 = (unsigned char *)SPI_TX_BASE; volatile unsigned short *spi_tx_16 = (unsigned short *)SPI_TX_BASE; volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned char *spi_rx_8 = (unsigned char *)SPI_RX_BASE; volatile unsigned short *spi_rx_16 = (unsigned short *)SPI_RX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various length (BE): 8, 16 and 32-bit...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control2_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control3_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 8-bit transfers */ spi_tx_8[0] = 0x5a; spi_tx_8[4] = 0x01; spi_tx_8[8] = 0x5a; spi_tx_8[12] = 0x01; /* TX 16-bit transfers */ spi_tx_16[0] = 0x5aa5; spi_tx_16[2] = 0x0102; spi_tx_16[4] = 0x5aa5; spi_tx_16[6] = 0x0102; /* TX 32-bit transfers */ spi_tx_32[0] = 0x5aa55aa5; spi_tx_32[1] = 0x01020304; spi_tx_32[2] = 0x5aa55aa5; spi_tx_32[3] = 0x01020304; /* Small delay */ busy_wait(1); /* Read RX 8-bit transfers */ if (spi_rx_8[ 0] != 0x5a) errors++; if (spi_rx_8[ 4] != 0x01) errors++; if (spi_rx_8[ 8] != 0x5a) errors++; if (spi_rx_8[12] != 0x01) errors++; /* Read RX 16-bit transfers */ if (spi_rx_16[0] != 0x5aa5) errors++; if (spi_rx_16[2] != 0x0102) errors++; if (spi_rx_16[4] != 0x5aa5) errors++; if (spi_rx_16[6] != 0x0102) errors++; /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x5aa55aa5) errors++; if (spi_rx_32[1] != 0x01020304) errors++; if (spi_rx_32[2] != 0x5aa55aa5) errors++; if (spi_rx_32[3] != 0x01020304) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI with various clk divider */ void test_spi_clk_divider(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various clk divider: 4, 8, 16 and 32...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 8 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control2_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 16 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control3_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 32 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x01020304; spi_tx_32[1] = 0x5aa55aa5; spi_tx_32[2] = 0x01020304; spi_tx_32[3] = 0x5aa55aa5; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x01020304) errors++; if (spi_rx_32[1] != 0x5aa55aa5) errors++; if (spi_rx_32[2] != 0x01020304) errors++; if (spi_rx_32[3] != 0x5aa55aa5) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI with various SPI modes */ void test_spi_modes(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various SPI modes: 0 and 3...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_3 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x5aa55aa5; spi_tx_32[1] = 0x5aa55aa5; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x5aa55aa5) errors++; if (spi_rx_32[1] != 0x5aa55aa5) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI with various bitorders */ void test_spi_bitorders(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI with various bitorders: MSB and LSB first...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); spi_mmap_ctrl_slot_control1_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_LSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 4 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0xff000000; spi_tx_32[1] = 0xff000000; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0xff000000) errors++; if (spi_rx_32[1] != 0xff000000) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI TX/RX levels */ void test_spi_tx_rx_levels(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int i; int errors = 0; int pattern; printf("Test SPI TX/RX levels...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 128 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ pattern = 0x00000001; for (i=0; i<16; i++){ if ((spi_mmap_ctrl_tx_status_read() >> 16) != i) errors++; spi_tx_32[0] = pattern; } /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ for (i=0; i<16; i++){ pattern = spi_rx_32[0]; if ((spi_mmap_ctrl_rx_status_read() >> 16) != (16-1-i)) errors++; } if ((spi_mmap_ctrl_tx_status_read() >> 16) != 0) errors++; if ((spi_mmap_ctrl_rx_status_read() >> 16) != 0) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI TX/RX IRQs */ void test_spi_tx_rx_irqs(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; int data __attribute__((unused)); printf("Test SPI TX/RX IRQs...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 128 * SPI_SLOT_DIVIDER ); /* Enable TX/RX EventManager */ spi_mmap_ev_enable_write(0); spi_mmap_ev_pending_write(spi_mmap_ev_pending_read()); spi_mmap_ev_enable_write(SPI_SLOT_EV_TX | SPI_SLOT_EV_RX); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x00000001; /* Small delay */ busy_wait(1); /* Verify TX/RX events */ if (spi_mmap_ev_pending_read() != (SPI_SLOT_EV_TX | SPI_SLOT_EV_RX)) errors++; /* Read RX 32-bit tranfers */ data = spi_rx_32[0]; /* Clear events */ spi_mmap_ev_pending_write(spi_mmap_ev_pending_read()); /* Verify TX/RX events */ if (spi_mmap_ev_pending_read() != 0) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); } /* Test SPI Back-to-Back */ void test_spi_back_to_back(void) { volatile unsigned int *spi_tx_32 = (unsigned int *)SPI_TX_BASE; volatile unsigned int *spi_rx_32 = (unsigned int *)SPI_RX_BASE; int errors = 0; printf("Test SPI Back-to-Back...\n"); /* Configure Slots */ spi_mmap_ctrl_slot_control0_write( 1 * SPI_SLOT_ENABLE | SPI_SLOT_MODE_0 * SPI_SLOT_MODE | SPI_SLOT_LENGTH_32B * SPI_SLOT_LENGTH | SPI_SLOT_BITORDER_MSB_FIRST * SPI_SLOT_BITORDER | 1 * SPI_SLOT_LOOPBACK | 8 * SPI_SLOT_DIVIDER ); /* Enable SPI Engine */ spi_mmap_tx_rx_engine_control_write(1 * SPI_TX_RX_ENGINE_ENABLE); /* TX 32-bit transfers */ spi_tx_32[0] = 0x00000001; spi_tx_32[0] = 0x00000002; /* Small delay */ busy_wait(1); /* Read RX 32-bit tranfers */ if (spi_rx_32[0] != 0x00000001) errors++; if (spi_rx_32[0] != 0x00000002) errors++; /* Disable SPI Engine */ spi_mmap_tx_rx_engine_control_write(0 * SPI_TX_RX_ENGINE_ENABLE); /* Result */ printf("errors: %d\n", errors); }
- Loading branch information