/*
 * 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);
}
Ejemplo n.º 3
0
/**
 * \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!");
}