diff options
Diffstat (limited to 'firmware/fx2/src/usrp1/spi.c')
| -rw-r--r-- | firmware/fx2/src/usrp1/spi.c | 472 | 
1 files changed, 472 insertions, 0 deletions
| diff --git a/firmware/fx2/src/usrp1/spi.c b/firmware/fx2/src/usrp1/spi.c new file mode 100644 index 000000000..0aaffea5d --- /dev/null +++ b/firmware/fx2/src/usrp1/spi.c @@ -0,0 +1,472 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING.  If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "spi.h" +#include "usrp_rev2_regs.h" + +static void +setup_enables (unsigned char enables) +{ +  // Software eanbles are active high. +  // Hardware enables are active low. + +  // Uhh, the CODECs are active low, but the FPGA is active high... +  enables ^= SPI_ENABLE_FPGA; + +  // KLUDGE: This code is fragile, but reasonably fast... +  // low three bits of enables go into port A +  USRP_PA = USRP_PA | (0x7 << 3);	// disable FPGA, CODEC_A, CODEC_B +  USRP_PA ^= (enables & 0x7) << 3;	// enable specified devs + +  // high four bits of enables go into port E +  USRP_PE = USRP_PE | (0xf << 4);	// disable TX_A, RX_A, TX_B, RX_B +  USRP_PE ^= (enables & 0xf0);		// enable specified devs +} + +#define disable_all()	setup_enables (0) + +void +init_spi (void) +{ +  disable_all ();		/* disable all devs	  */ +  bitS_OUT = 0;			/* idle state has CLK = 0 */ +} + +#if 0 +static unsigned char +count_bits8 (unsigned char v) +{ +  static unsigned char count4[16] = { +    0,	// 0 +    1,	// 1 +    1,	// 2 +    2,	// 3 +    1,	// 4 +    2,	// 5 +    2,	// 6 +    3,	// 7 +    1,	// 8 +    2,	// 9 +    2,	// a +    3,	// b +    2,	// c +    3,	// d +    3,	// e +    4	// f +  }; +  return count4[v & 0xf] + count4[(v >> 4) & 0xf]; +} + +#else + +static unsigned char +count_bits8 (unsigned char v) +{ +  unsigned char count = 0; +  if (v & (1 << 0)) count++; +  if (v & (1 << 1)) count++; +  if (v & (1 << 2)) count++; +  if (v & (1 << 3)) count++; +  if (v & (1 << 4)) count++; +  if (v & (1 << 5)) count++; +  if (v & (1 << 6)) count++; +  if (v & (1 << 7)) count++; +  return count; +} +#endif + +static void +write_byte_msb (unsigned char v); + +unsigned char +transact_byte_msb (unsigned char v); + +static void +write_bytes_msb (const xdata unsigned char *buf, unsigned char len); + +static void +read_bytes_msb (xdata unsigned char *buf, unsigned char len); + +static void +transact_bytes_msb (xdata unsigned char *buf, unsigned char len); + +// returns non-zero if successful, else 0 +unsigned char +spi_read (unsigned char header_hi, unsigned char header_lo, +	  unsigned char enables, unsigned char format, +	  xdata unsigned char *buf, unsigned char len) +{ +  if (count_bits8 (enables) > 1) +    return 0;		// error, too many enables set + +  setup_enables (enables); + +  if (format & SPI_FMT_LSB){		// order: LSB +#if 1 +    return 0;		// error, not implemented +#else +    switch (format & SPI_FMR_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_lsb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_lsb (header_lo); +      write_byte_lsb (header_hi); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      read_bytes_lsb (buf, len); +#endif +  } + +  else {		// order: MSB + +    switch (format & SPI_FMT_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_msb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_msb (header_hi); +      write_byte_msb (header_lo); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      read_bytes_msb (buf, len); +  } + +  disable_all (); +  return 1;		// success +} + + +// returns non-zero if successful, else 0 +unsigned char +spi_write (unsigned char header_hi, unsigned char header_lo, +	   unsigned char enables, unsigned char format, +	   const xdata unsigned char *buf, unsigned char len) +{ +  setup_enables (enables); + +  if (format & SPI_FMT_LSB){		// order: LSB +#if 1 +    return 0;		// error, not implemented +#else +    switch (format & SPI_FMR_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_lsb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_lsb (header_lo); +      write_byte_lsb (header_hi); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      write_bytes_lsb (buf, len); +#endif +  } + +  else {		// order: MSB + +    switch (format & SPI_FMT_HDR_MASK){ +    case SPI_FMT_HDR_0: +      break; +    case SPI_FMT_HDR_1: +      write_byte_msb (header_lo); +      break; +    case SPI_FMT_HDR_2: +      write_byte_msb (header_hi); +      write_byte_msb (header_lo); +      break; +    default: +      return 0;		// error +    } +    if (len != 0) +      write_bytes_msb (buf, len); +  } + +  disable_all (); +  return 1;		// success +} + +unsigned char +spi_transact (unsigned char data0, unsigned char data1, +              unsigned char data2, unsigned char data3, +              unsigned char enables, xdata unsigned char *buf, +              unsigned char len) +{ +  if (count_bits8 (enables) > 1) +    return 0;		// error, too many enables set + +  if (len > 4) +    return 0; + +  setup_enables (enables); + +  buf[0] = data0; +  buf[1] = data1; +  buf[2] = data2;  +  buf[3] = data3;  + +  if (len != 0) +    transact_bytes_msb(buf, len); + +  disable_all (); +  return 1;		// success +} + +static unsigned char  +transact_byte_msb (unsigned char v) +{ +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN;                 // read into bottom bit +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7); +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  return v; +} + +static void +transact_bytes_msb (xdata unsigned char *buf, unsigned char len) +{ +  while (len-- != 0){ +    *buf++ = transact_byte_msb (*buf); +  } +} + +static void +write_byte_msb (unsigned char v) +{ +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; + +  v = (v << 1) | (v >> 7);	// rotate left (MSB into bottom bit) +  bitS_OUT = v & 0x1; +  bitS_CLK = 1; +  bitS_CLK = 0; +} + +static void +write_bytes_msb (const xdata unsigned char *buf, unsigned char len) +{ +  while (len-- != 0){ +    write_byte_msb (*buf++); +  } +} + +#if 0 +/* + * This is incorrectly compiled by SDCC 2.4.0 + */ +static unsigned char +read_byte_msb (void) +{ +  unsigned char v = 0; + +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  v = v << 1; +  bitS_CLK = 1; +  v |= bitS_IN; +  bitS_CLK = 0; + +  return v; +} +#else +static unsigned char +read_byte_msb (void) _naked +{ +  _asm +	clr	a + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	setb	_bitS_CLK +        mov	c, _bitS_IN +	rlc	a +	clr	_bitS_CLK + +	mov	dpl,a +	ret +  _endasm; +} +#endif + +static void +read_bytes_msb (xdata unsigned char *buf, unsigned char len) +{ +  while (len-- != 0){ +    *buf++ = read_byte_msb (); +  } +} + | 
