/* -*- c++ -*- */
|
/* -*- c++ -*- */
|
/*
|
/*
|
* Copyright 2004,2006 Free Software Foundation, Inc.
|
* Copyright 2004,2006 Free Software Foundation, Inc.
|
*
|
*
|
* This file is part of GNU Radio
|
* This file is part of GNU Radio
|
*
|
*
|
* GNU Radio is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
* the Free Software Foundation; either version 3, or (at your option)
|
* the Free Software Foundation; either version 3, or (at your option)
|
* any later version.
|
* any later version.
|
*
|
*
|
* GNU Radio is distributed in the hope that it will be useful,
|
* GNU Radio is distributed in the hope that it will be useful,
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
*
|
*
|
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
* along with GNU Radio; see the file COPYING. If not, write to
|
* along with GNU Radio; see the file COPYING. If not, write to
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
*/
|
*/
|
/************************************************************/
|
/************************************************************/
|
/** \file spi.c
|
/** \file spi.c
|
*************************************************************
|
*************************************************************
|
* \brief SPI bus functions
|
* \brief SPI bus functions
|
*
|
*
|
* \details Library to communicate with SPI devices
|
* \details Library to communicate with SPI devices
|
*
|
*
|
* \author GNU Radio guys
|
* \author GNU Radio guys
|
*/
|
*/
|
|
|
#include "spi.h"
|
#include "spi.h"
|
#include "debugprint.h"
|
#include "debugprint.h"
|
|
|
#if 0
|
#if 0
|
/*
|
/*
|
static unsigned char
|
static unsigned char
|
count_bits8 (unsigned char v)
|
count_bits8 (unsigned char v)
|
{
|
{
|
static unsigned char count4[16] = {
|
static unsigned char count4[16] = {
|
0, // 0
|
0, // 0
|
1, // 1
|
1, // 1
|
1, // 2
|
1, // 2
|
2, // 3
|
2, // 3
|
1, // 4
|
1, // 4
|
2, // 5
|
2, // 5
|
2, // 6
|
2, // 6
|
3, // 7
|
3, // 7
|
1, // 8
|
1, // 8
|
2, // 9
|
2, // 9
|
2, // a
|
2, // a
|
3, // b
|
3, // b
|
2, // c
|
2, // c
|
3, // d
|
3, // d
|
3, // e
|
3, // e
|
4 // f
|
4 // f
|
};
|
};
|
return count4[v & 0xf] + count4[(v >> 4) & 0xf];
|
return count4[v & 0xf] + count4[(v >> 4) & 0xf];
|
}
|
}
|
*/
|
*/
|
#else
|
#else
|
|
|
/** \brief internal helper function to count the number of active (1) bits in a byte */
|
/** \brief internal helper function to count the number of active (1) bits in a byte */
|
static unsigned char
|
static unsigned char
|
count_bits8 (unsigned char v)
|
count_bits8 (unsigned char v)
|
{
|
{
|
unsigned char count = 0;
|
unsigned char count = 0;
|
if (v & (1 << 0)) count++;
|
if (v & (1 << 0)) count++;
|
if (v & (1 << 1)) count++;
|
if (v & (1 << 1)) count++;
|
if (v & (1 << 2)) count++;
|
if (v & (1 << 2)) count++;
|
if (v & (1 << 3)) count++;
|
if (v & (1 << 3)) count++;
|
if (v & (1 << 4)) count++;
|
if (v & (1 << 4)) count++;
|
if (v & (1 << 5)) count++;
|
if (v & (1 << 5)) count++;
|
if (v & (1 << 6)) count++;
|
if (v & (1 << 6)) count++;
|
if (v & (1 << 7)) count++;
|
if (v & (1 << 7)) count++;
|
return count;
|
return count;
|
}
|
}
|
#endif
|
#endif
|
|
|
|
|
static void
|
static void
|
setup_enables (unsigned char enables)
|
setup_enables (unsigned char enables)
|
{
|
{
|
// Software eanbles are active high.
|
// Software eanbles are active high.
|
// Hardware enables are active low.
|
// Hardware enables are active low.
|
|
|
if(count_bits8(enables) > 1) {
|
if(count_bits8(enables) > 1) {
|
print_info("too many enables acitve\n");
|
print_info("too many enables acitve\n");
|
return;
|
return;
|
}
|
}
|
else {
|
else {
|
enables &= bmSPI_CS_MASK;
|
enables &= bmSPI_CS_MASK;
|
SPI_CS_PORT |= bmSPI_CS_MASK; //disable all chipselect signals
|
SPI_CS_PORT |= bmSPI_CS_MASK; //disable all chipselect signals
|
SPI_CS_PORT &= ~enables;
|
SPI_CS_PORT &= ~enables;
|
}
|
}
|
}
|
}
|
|
|
|
/** \brief disables all devices on the SPI bus */
|
#define disable_all() setup_enables (0)
|
#define disable_all() setup_enables (0)
|
|
|
void
|
void
|
init_spi (void)
|
init_spi (void)
|
{
|
{
|
disable_all (); /* disable all devs */
|
disable_all (); /* disable all devs */
|
bitSPI_MOSI = 0; /* idle state has CLK = 0 */
|
bitSPI_MOSI = 0; /* idle state has CLK = 0 */
|
}
|
}
|
static void
|
static void
|
write_byte_msb (unsigned char v);
|
write_byte_msb (unsigned char v);
|
|
|
static void
|
static void
|
write_bytes_msb (const xdata unsigned char *buf, unsigned char len);
|
write_bytes_msb (const xdata unsigned char *buf, unsigned char len);
|
|
|
static void
|
static void
|
read_bytes_msb (xdata unsigned char *buf, unsigned char len);
|
read_bytes_msb (xdata unsigned char *buf, unsigned char len);
|
|
|
|
|
// returns non-zero if successful, else 0
|
// returns non-zero if successful, else 0
|
unsigned char
|
unsigned char
|
spi_read (unsigned char header_hi, unsigned char header_lo,
|
spi_read (unsigned char header_hi, unsigned char header_lo,
|
unsigned char enables, unsigned char format,
|
unsigned char enables, unsigned char format,
|
xdata unsigned char *buf, unsigned char len)
|
xdata unsigned char *buf, unsigned char len)
|
{
|
{
|
if (count_bits8 (enables) > 1)
|
if (count_bits8 (enables) > 1)
|
return 0; // error, too many enables set
|
return 0; // error, too many enables set
|
|
|
setup_enables (enables);
|
setup_enables (enables);
|
/*
|
/*
|
if (format & bmSPI_FMT_LSB){ // order: LSB
|
if (format & bmSPI_FMT_LSB){ // order: LSB
|
#if 1
|
#if 1
|
return 0; // error, not implemented
|
return 0; // error, not implemented
|
#else
|
#else
|
switch (format & bmSPI_HEADER){
|
switch (format & bmSPI_HEADER){
|
case SPI_HEADER_0:
|
case SPI_HEADER_0:
|
break;
|
break;
|
case bmSPI_HEADER_1:
|
case bmSPI_HEADER_1:
|
write_byte_lsb (header_lo);
|
write_byte_lsb (header_lo);
|
break;
|
break;
|
case bmSPI_HEADER_2:
|
case bmSPI_HEADER_2:
|
write_byte_lsb (header_lo);
|
write_byte_lsb (header_lo);
|
write_byte_lsb (header_hi);
|
write_byte_lsb (header_hi);
|
break;
|
break;
|
default:
|
default:
|
return 0; // error
|
return 0; // error
|
}
|
}
|
if (len != 0)
|
if (len != 0)
|
read_bytes_lsb (buf, len);
|
read_bytes_lsb (buf, len);
|
#endif
|
#endif
|
}
|
}
|
|
|
else { // order: MSB
|
else { // order: MSB
|
*/
|
*/
|
switch (format & bmSPI_HEADER){
|
switch (format & bmSPI_HEADER){
|
case bmSPI_HEADER_0:
|
case bmSPI_HEADER_0:
|
break;
|
break;
|
case bmSPI_HEADER_1:
|
case bmSPI_HEADER_1:
|
write_byte_msb (header_lo);
|
write_byte_msb (header_lo);
|
break;
|
break;
|
case bmSPI_HEADER_2:
|
case bmSPI_HEADER_2:
|
write_byte_msb (header_hi);
|
write_byte_msb (header_hi);
|
write_byte_msb (header_lo);
|
write_byte_msb (header_lo);
|
break;
|
break;
|
default:
|
default:
|
return 0; // error
|
return 0; // error
|
}
|
}
|
if (len != 0)
|
if (len != 0)
|
read_bytes_msb (buf, len);
|
read_bytes_msb (buf, len);
|
//}
|
//}
|
|
|
disable_all ();
|
disable_all ();
|
return 1; // success
|
return 1; // success
|
}
|
}
|
|
|
|
|
// returns non-zero if successful, else 0
|
// returns non-zero if successful, else 0
|
unsigned char
|
unsigned char
|
spi_write (unsigned char header_hi, unsigned char header_lo,
|
spi_write (unsigned char header_hi, unsigned char header_lo,
|
unsigned char enables, unsigned char format,
|
unsigned char enables, unsigned char format,
|
const xdata unsigned char *buf, unsigned char len)
|
const xdata unsigned char *buf, unsigned char len)
|
{
|
{
|
setup_enables (enables);
|
setup_enables (enables);
|
|
|
/* if (format & bmSPI_FORMAT_LSB){ // order: LSB
|
/* if (format & bmSPI_FORMAT_LSB){ // order: LSB
|
#if 1
|
#if 1
|
return 0; // error, not implemented
|
return 0; // error, not implemented
|
#else
|
#else
|
switch (format & bmSPI_HEADER){
|
switch (format & bmSPI_HEADER){
|
case bmSPI_HEADER_0:
|
case bmSPI_HEADER_0:
|
break;
|
break;
|
case bmSPI_HEADER_1:
|
case bmSPI_HEADER_1:
|
write_byte_lsb (header_lo);
|
write_byte_lsb (header_lo);
|
break;
|
break;
|
case bmSPI_HEADER_2:
|
case bmSPI_HEADER_2:
|
write_byte_lsb (header_lo);
|
write_byte_lsb (header_lo);
|
write_byte_lsb (header_hi);
|
write_byte_lsb (header_hi);
|
break;
|
break;
|
default:
|
default:
|
return 0; // error
|
return 0; // error
|
}
|
}
|
if (len != 0)
|
if (len != 0)
|
write_bytes_lsb (buf, len);
|
write_bytes_lsb (buf, len);
|
#endif
|
#endif
|
}
|
}
|
|
|
else { // order: MSB
|
else { // order: MSB
|
*/
|
*/
|
switch (format & bmSPI_HEADER){
|
switch (format & bmSPI_HEADER){
|
case bmSPI_HEADER_0:
|
case bmSPI_HEADER_0:
|
break;
|
break;
|
case bmSPI_HEADER_1:
|
case bmSPI_HEADER_1:
|
write_byte_msb (header_lo);
|
write_byte_msb (header_lo);
|
break;
|
break;
|
case bmSPI_HEADER_2:
|
case bmSPI_HEADER_2:
|
write_byte_msb (header_hi);
|
write_byte_msb (header_hi);
|
write_byte_msb (header_lo);
|
write_byte_msb (header_lo);
|
break;
|
break;
|
default:
|
default:
|
return 0; // error
|
return 0; // error
|
}
|
}
|
if (len != 0)
|
if (len != 0)
|
write_bytes_msb (buf, len);
|
write_bytes_msb (buf, len);
|
//}
|
//}
|
|
|
disable_all ();
|
disable_all ();
|
return 1; // success
|
return 1; // success
|
}
|
}
|
|
|
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
|
|
static void
|
static void
|
write_byte_msb (unsigned char v)
|
write_byte_msb (unsigned char v)
|
{
|
{
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_MOSI = v & 0x1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
}
|
}
|
|
|
static void
|
static void
|
write_bytes_msb (const xdata unsigned char *buf, unsigned char len)
|
write_bytes_msb (const xdata unsigned char *buf, unsigned char len)
|
{
|
{
|
while (len-- != 0){
|
while (len-- != 0){
|
write_byte_msb (*buf++);
|
write_byte_msb (*buf++);
|
}
|
}
|
}
|
}
|
|
|
#if 0
|
#if 0
|
/*
|
/*
|
* This is incorrectly compiled by SDCC 2.4.0
|
* This is incorrectly compiled by SDCC 2.4.0
|
*/
|
*/
|
/*static unsigned char
|
/*static unsigned char
|
read_byte_msb (void)
|
read_byte_msb (void)
|
{
|
{
|
unsigned char v = 0;
|
unsigned char v = 0;
|
|
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
v = v << 1;
|
v = v << 1;
|
bitSPI_CLK = 1;
|
bitSPI_CLK = 1;
|
v |= bitSPI_MISO;
|
v |= bitSPI_MISO;
|
bitSPI_CLK = 0;
|
bitSPI_CLK = 0;
|
|
|
return v;
|
return v;
|
} */
|
} */
|
#else
|
#else
|
static unsigned char
|
static unsigned char
|
read_byte_msb (void) _naked
|
read_byte_msb (void) _naked
|
{
|
{
|
_asm
|
_asm
|
clr a
|
clr a
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
setb _bitSPI_CLK
|
setb _bitSPI_CLK
|
mov c, _bitSPI_MISO
|
mov c, _bitSPI_MISO
|
rlc a
|
rlc a
|
clr _bitSPI_CLK
|
clr _bitSPI_CLK
|
|
|
mov dpl,a
|
mov dpl,a
|
ret
|
ret
|
_endasm;
|
_endasm;
|
}
|
}
|
#endif
|
#endif
|
|
|
static void
|
static void
|
read_bytes_msb (xdata unsigned char *buf, unsigned char len)
|
read_bytes_msb (xdata unsigned char *buf, unsigned char len)
|
{
|
{
|
while (len-- != 0){
|
while (len-- != 0){
|
*buf++ = read_byte_msb ();
|
*buf++ = read_byte_msb ();
|
}
|
}
|
}
|
}
|
|
|
|
|