/* * Transfer (i.e. exchange) one "word" with selected SPI device. * Typically one word is 8-bits (an octet), but it does not need to be, * this function is word-width agnostic - when using the SSC. * However, for PIO bit-banging, then one word is explicitly * unconditionally assumed to be exactly 8-bits in length. * * input: "out" is word to be send to slave SPI device * returns: one word read from the slave SPI device * * It is the caller's responsibility to ensure that the * chip select (SPI_NOTCS) is correctly asserted. */ static unsigned int spi_xfer_one_word(const unsigned int out) { unsigned int in = 0; #if defined(CONFIG_SOFT_SPI) /* Use PIO Bit-Banging for SPI */ signed int i; for(i=7; i>=0; i--) /* for each bit in turn ... */ { /* do 8 bits, msb first */ SPI_SCL(0); /* SPI_CLK = low */ SPI_SDA(out & (1u<<i)); /* output next bit on SPI_DOUT */ SPI_DELAY; /* clock low cycle */ SPI_SCL(1); /* SPI_CLK = high */ SPI_DELAY; /* sample on RISING clock edge */ in <<= 1; /* shift */ in |= SPI_READ; /* get next bit from SPI_DIN */ } #else /* Use SSC for SPI */ /* write out data 'out' */ ssc_write(SSC_TBUF, out); /* wait for Receive Buffer Full flag to be asserted */ while ((ssc_read(SSC_STAT) & SSC_STAT_RIR) == 0) { ; /* busy poll - do nothing */ } /* read in data */ in = ssc_read(SSC_RBUF); #endif /* CONFIG_SOFT_SPI */ /* return exchanged data */ return in; }
/* * initialise the SSC to talk to the slave SPI device. */ extern void spi_init(void) { //DECLARE_GLOBAL_DATA_PTR; spi_chipsel_type const chipsel = spi_chipsel[0]; /* SPI Device #0 */ #if !defined(CONFIG_SOFT_SPI) /* Use SSC for SPI */ unsigned long reg; const unsigned long bits_per_word = 8; /* one word == 8-bits */ const unsigned long mode = CFG_STM_SPI_MODE /* | SPI_LOOP */; //const unsigned long fcomms = gd->bd->bi_emifrq*1000*1000; const unsigned long hz = CFG_STM_SPI_FREQUENCY; //unsigned long sscbrg = fcomms/(2*hz); #endif /* CONFIG_SOFT_SPI */ /*init pio15.0-pio15.3*/ configSpi(); /* de-assert SPI CS */ (*chipsel)(0); #if !defined(CONFIG_SOFT_SPI) /* Use SSC for SPI */ /* program the SSC's Baud-Rate Generator */ if ((sscbrg < 0x07u) || (sscbrg > (0x1u << 16))) { printk("ERROR: Unable to set SSC buad-rate generator to 0x%04x\n", sscbrg); return; } /* TODO: program pre-scaler for slower baud rates */ if (sscbrg == (0x1 << 16)) /* 16-bit counter wraps */ { sscbrg = 0x0; /* slowest possible clock frequency */ } ssc_write(SSC_BRG,sscbrg); #if 0 /* QQQ */ printk("info: fcomms=%uMHz, SPI=%uHz, brg=0x%04x\n", fcomms/1000/1000, hz, sscbrg); #endif /* Disable I2C sub-system */ ssc_write( SSC_I2C, 0x0); /* Perform a S/W reset the SSC */ reg = ssc_read( SSC_CON); reg |= SSC_CON_SR; /* enable software reset */ ssc_write( SSC_CON, reg); udelay(1); /* let reset propagate */ reg = ssc_read( SSC_CON); reg &= ~SSC_CON_SR; /* disable software reset */ ssc_write( SSC_CON, reg); /* Configure & enable the SSC's control register */ reg = ssc_read(SSC_CON); reg |= SSC_CON_EN; /* Enable the SSC */ reg |= SSC_CON_MS; /* set SSC as the SPI master */ if (mode & SPI_CPOL) reg |= SSC_CON_PO; /* Clock idles at logic 1 */ else reg &= ~SSC_CON_PO; /* Clock idles at logic 0 */ if (mode & SPI_CPHA) reg |= SSC_CON_PH; /* Pulse in first half-cycle */ else reg &= ~SSC_CON_PH; /* Pulse in second half-cycle */ if (mode & SPI_LSB_FIRST) reg &= ~SSC_CON_HB; /* LSB first */ else reg |= SSC_CON_HB; /* MSB first */ if (mode & SPI_LOOP) reg |= SSC_CON_LPB; /* put SSC in loop-back mode */ else reg &= ~SSC_CON_LPB; /* remove SSC from loop-back mode */ reg &= ~0x0ful; /* set bit width */ reg |= (bits_per_word - 1ul); /* set bit width */ ssc_write(SSC_CON,reg); /* clear the status register */ (void)ssc_read(SSC_RBUF); #endif /* CONFIG_SOFT_SPI */ /* now probe the serial flash, to ensure it is the correct one */ spi_probe_serial_flash(chipsel); }
/** * \brief Test Synchronous Serial Controller. * This test sets SSC module in the loop mode and check the receiver data * whether it's the same as the transmit data. * * \param test Current test case. */ static void run_ssc_test(const struct test_case *test) { uint32_t ul_mck; clock_opt_t tx_clk_option; clock_opt_t rx_clk_option; data_frame_opt_t rx_data_frame_option; data_frame_opt_t tx_data_frame_option; /* Initialize the local variable. */ ul_mck = 0; memset((uint8_t *)&rx_clk_option, 0, sizeof(clock_opt_t)); memset((uint8_t *)&rx_data_frame_option, 0, sizeof(data_frame_opt_t)); memset((uint8_t *)&tx_clk_option, 0, sizeof(clock_opt_t)); memset((uint8_t *)&tx_data_frame_option, 0, sizeof(data_frame_opt_t)); /* Initialize the SSC module and work in loop mode. */ pmc_enable_periph_clk(ID_SSC); ssc_reset(SSC); ul_mck = sysclk_get_cpu_hz(); ssc_set_clock_divider(SSC, SSC_BIT_RATE, ul_mck); /* Transmitter clock mode configuration. */ tx_clk_option.ul_cks = SSC_TCMR_CKS_MCK; tx_clk_option.ul_cko = SSC_TCMR_CKO_CONTINUOUS; tx_clk_option.ul_cki = 0; tx_clk_option.ul_ckg = SSC_TCMR_CKG_NONE; tx_clk_option.ul_start_sel = SSC_TCMR_START_CONTINUOUS; tx_clk_option.ul_sttdly = 0; tx_clk_option.ul_period = 0; /* Transmitter frame mode configuration. */ tx_data_frame_option.ul_datlen = BIT_LEN_PER_CHANNEL - 1; tx_data_frame_option.ul_msbf = SSC_TFMR_MSBF; tx_data_frame_option.ul_datnb = 0; tx_data_frame_option.ul_fslen = 0; tx_data_frame_option.ul_fslen_ext = 0; tx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_TOGGLING; tx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE; /* Configure the SSC transmitter. */ ssc_set_transmitter(SSC, &tx_clk_option, &tx_data_frame_option); /* Receiver clock mode configuration. */ rx_clk_option.ul_cks = SSC_RCMR_CKS_TK; rx_clk_option.ul_cko = SSC_RCMR_CKO_NONE; rx_clk_option.ul_cki = 0; rx_clk_option.ul_ckg = SSC_TCMR_CKG_NONE; rx_clk_option.ul_start_sel = SSC_RCMR_START_RF_EDGE; rx_clk_option.ul_sttdly = 0; rx_clk_option.ul_period = 0; /* Receiver frame mode configuration. */ rx_data_frame_option.ul_datlen = BIT_LEN_PER_CHANNEL - 1; rx_data_frame_option.ul_msbf = SSC_TFMR_MSBF; rx_data_frame_option.ul_datnb = 0; rx_data_frame_option.ul_fslen = 0; rx_data_frame_option.ul_fslen_ext = 0; rx_data_frame_option.ul_fsos = SSC_TFMR_FSOS_NONE; rx_data_frame_option.ul_fsedge = SSC_TFMR_FSEDGE_POSITIVE; /* Configure the SSC receiver. */ ssc_set_receiver(SSC, &rx_clk_option, &rx_data_frame_option); /* Enable the loop mode. */ ssc_set_loop_mode(SSC); /* Enable the tx and rx function. */ ssc_enable_rx(SSC); ssc_enable_tx(SSC); /* Configure the RX interrupt. */ ssc_enable_interrupt(SSC, SSC_IER_RXRDY); /* Enable SSC interrupt line from the core */ NVIC_DisableIRQ(SSC_IRQn); NVIC_ClearPendingIRQ(SSC_IRQn); NVIC_SetPriority(SSC_IRQn, SSC_IRQ_PRIO); NVIC_EnableIRQ(SSC_IRQn); for (g_uc_tx_index = 0; g_uc_tx_index < BUFFER_SIZE; g_uc_tx_index++) { ssc_write(SSC, g_uc_tx_buff[g_uc_tx_index]); } while (!g_uc_rx_done) { } test_assert_true(test, (memcmp(g_uc_rx_buff, g_uc_tx_buff, BUFFER_SIZE) == 0), "Test: SSC received data is not the same as the transmit data!"); }