|
@ -111,6 +111,9 @@ |
|
|
#define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU/1000000) / 1000) |
|
|
#define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU/1000000) / 1000) |
|
|
|
|
|
|
|
|
typedef uint8_t (*pfnSpiTransfer) (uint8_t b); |
|
|
typedef uint8_t (*pfnSpiTransfer) (uint8_t b); |
|
|
|
|
|
typedef void (*pfnSpiRxBlock)(uint8_t* buf, uint32_t nbyte); |
|
|
|
|
|
typedef void (*pfnSpiTxBlock)(const uint8_t* buf, uint32_t nbyte); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------------- Macros to be able to access definitions from asm */ |
|
|
/* ---------------- Macros to be able to access definitions from asm */ |
|
|
|
|
|
|
|
@ -183,26 +186,32 @@ |
|
|
/* Bit 0 */ |
|
|
/* Bit 0 */ |
|
|
" str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
" str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" nop" "\n\t" |
|
|
" nop" "\n\t" /* Result will be 0 */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
: [mosi_mask]"+r"( MOSI_MASK ), |
|
|
: [idx]"+r"( idx ) |
|
|
[mosi_port]"+r"( MOSI_PORT_PLUS30 ), |
|
|
: [txval]"r"( bout ) , |
|
|
[sck_mask]"+r"( SCK_MASK ), |
|
|
[mosi_mask]"r"( MOSI_MASK ), |
|
|
[sck_port]"+r"( SCK_PORT_PLUS30 ), |
|
|
[mosi_port]"r"( MOSI_PORT_PLUS30 ), |
|
|
[idx]"+r"( idx ), |
|
|
[sck_mask]"r"( SCK_MASK ), |
|
|
[txval]"+r"( bout ) |
|
|
[sck_port]"r"( SCK_PORT_PLUS30 ) |
|
|
: |
|
|
|
|
|
: "cc" |
|
|
: "cc" |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Calculates the bit band alias address and returns a pointer address to word.
|
|
|
|
|
|
// addr: The byte address of bitbanding bit.
|
|
|
|
|
|
// bit: The bit position of bitbanding bit.
|
|
|
|
|
|
#define BITBAND_ADDRESS(addr, bit) \ |
|
|
|
|
|
(((uint32_t)(addr) & 0xF0000000) + 0x02000000 + ((uint32_t)(addr)&0xFFFFF)*32 + (bit)*4) |
|
|
|
|
|
|
|
|
// run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
|
|
|
// run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
|
|
|
static uint8_t spiTransferRx0(uint8_t bout) { // using Mode 0
|
|
|
static uint8_t spiTransferRx0(uint8_t bout) { // using Mode 0
|
|
|
int bin = 0, work = 0; |
|
|
register uint32_t bin; |
|
|
register uint32_t MISO_PORT_PLUS3C = ((uint32_t) PORT(MISO_PIN)) + 0x3C; /* PDSR of port */ |
|
|
register uint32_t work; |
|
|
|
|
|
register uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(MISO_PIN))+0x3C, PIN_SHIFT(MISO_PIN)); /* PDSR of port in bitband area */ |
|
|
register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ |
|
|
register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ |
|
|
register uint32_t SCK_MASK = PIN_MASK(SCK_PIN); |
|
|
register uint32_t SCK_MASK = PIN_MASK(SCK_PIN); |
|
|
UNUSED(bout); |
|
|
UNUSED(bout); |
|
@ -213,70 +222,61 @@ |
|
|
|
|
|
|
|
|
/* bit 7 */ |
|
|
/* bit 7 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#7,#1" "\n\t" /* Store read bit as the bit 7 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 6 */ |
|
|
/* bit 6 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#6,#1" "\n\t" /* Store read bit as the bit 6 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 5 */ |
|
|
/* bit 5 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#5,#1" "\n\t" /* Store read bit as the bit 5 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 4 */ |
|
|
/* bit 4 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#4,#1" "\n\t" /* Store read bit as the bit 4 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 3 */ |
|
|
/* bit 3 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#3,#1" "\n\t" /* Store read bit as the bit 3 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 2 */ |
|
|
/* bit 2 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#2,#1" "\n\t" /* Store read bit as the bit 2 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 1 */ |
|
|
/* bit 1 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#1,#1" "\n\t" /* Store read bit as the bit 1 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 0 */ |
|
|
/* bit 0 */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
" ldr %[work],[%[miso_port]]" "\n\t" /* PDSR */ |
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */ |
|
|
" bfi %[bin],%[work],#0,#1" "\n\t" /* Store read bit as the bit 0 */ |
|
|
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */ |
|
|
|
|
|
|
|
|
|
|
|
: [miso_port]"+r"( MISO_PORT_PLUS3C ), |
|
|
: [bin]"+r"(bin), |
|
|
[sck_mask]"+r"( SCK_MASK ), |
|
|
|
|
|
[sck_port]"+r"( SCK_PORT_PLUS30 ), |
|
|
|
|
|
[bin]"+r"(bin), |
|
|
|
|
|
[work]"+r"(work) |
|
|
[work]"+r"(work) |
|
|
: [miso_shift]"M"( PIN_SHIFT(MISO_PIN) + 1 ) /* So we move to the carry */ |
|
|
: [bitband_miso_port]"r"( BITBAND_MISO_PORT ), |
|
|
|
|
|
[sck_mask]"r"( SCK_MASK ), |
|
|
|
|
|
[sck_port]"r"( SCK_PORT_PLUS30 ) |
|
|
: "cc" |
|
|
: "cc" |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
return (uint8_t)bin; |
|
|
return bin; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// run at ~4Mhz
|
|
|
// run at ~4Mhz
|
|
@ -317,10 +317,182 @@ |
|
|
return b; |
|
|
return b; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Pointers to generic functions
|
|
|
// Pointers to generic functions for byte transfers
|
|
|
static pfnSpiTransfer spiTransferTx = spiTransferX; |
|
|
static pfnSpiTransfer spiTransferTx = spiTransferX; |
|
|
static pfnSpiTransfer spiTransferRx = spiTransferX; |
|
|
static pfnSpiTransfer spiTransferRx = spiTransferX; |
|
|
|
|
|
|
|
|
|
|
|
// Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
|
|
|
|
|
|
static void spiTxBlock0(const uint8_t* ptr, uint32_t todo) { |
|
|
|
|
|
register uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(MOSI_PIN)) + 0x30; /* SODR of port */ |
|
|
|
|
|
register uint32_t MOSI_MASK = PIN_MASK(MOSI_PIN); |
|
|
|
|
|
register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ |
|
|
|
|
|
register uint32_t SCK_MASK = PIN_MASK(SCK_PIN); |
|
|
|
|
|
register uint32_t work; |
|
|
|
|
|
register uint32_t txval; |
|
|
|
|
|
|
|
|
|
|
|
/* The software SPI routine */ |
|
|
|
|
|
__asm__ __volatile__( |
|
|
|
|
|
".syntax unified" "\n\t" // is to prevent CM0,CM1 non-unified syntax
|
|
|
|
|
|
|
|
|
|
|
|
" loop%=:" "\n\t" |
|
|
|
|
|
" ldrb.w %[txval], [%[ptr]], #1" "\n\t" /* Load value to send, increment buffer */ |
|
|
|
|
|
" mvn %[txval],%[txval]" "\n\t" /* Negate value */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 7 */ |
|
|
|
|
|
" ubfx %[work],%[txval],#7,#1" "\n\t" /* Place bit 7 in bit 0 of work*/ |
|
|
|
|
|
|
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#6,#1" "\n\t" /* Place bit 6 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 6 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#5,#1" "\n\t" /* Place bit 5 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 5 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#4,#1" "\n\t" /* Place bit 4 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 4 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#3,#1" "\n\t" /* Place bit 3 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 3 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#2,#1" "\n\t" /* Place bit 2 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 2 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#1,#1" "\n\t" /* Place bit 1 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 1 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ubfx %[work],%[txval],#0,#1" "\n\t" /* Place bit 0 in bit 0 of work*/ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
|
|
|
|
|
|
/* Bit 0 */ |
|
|
|
|
|
" str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" subs %[todo],#1" "\n\t" /* Decrement count of pending words to send, update status */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bne.n loop%=" "\n\t" /* Repeat until done */ |
|
|
|
|
|
|
|
|
|
|
|
: [ptr]"+r" ( ptr ) , |
|
|
|
|
|
[todo]"+r" ( todo ) , |
|
|
|
|
|
[work]"+r"( work ) , |
|
|
|
|
|
[txval]"+r"( txval ) |
|
|
|
|
|
: [mosi_mask]"r"( MOSI_MASK ), |
|
|
|
|
|
[mosi_port]"r"( MOSI_PORT_PLUS30 ), |
|
|
|
|
|
[sck_mask]"r"( SCK_MASK ), |
|
|
|
|
|
[sck_port]"r"( SCK_PORT_PLUS30 ) |
|
|
|
|
|
: "cc" |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void spiRxBlock0(uint8_t* ptr, uint32_t todo) { |
|
|
|
|
|
register uint32_t bin; |
|
|
|
|
|
register uint32_t work; |
|
|
|
|
|
register uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(MISO_PIN))+0x3C, PIN_SHIFT(MISO_PIN)); /* PDSR of port in bitband area */ |
|
|
|
|
|
register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */ |
|
|
|
|
|
register uint32_t SCK_MASK = PIN_MASK(SCK_PIN); |
|
|
|
|
|
|
|
|
|
|
|
/* The software SPI routine */ |
|
|
|
|
|
__asm__ __volatile__( |
|
|
|
|
|
".syntax unified" "\n\t" // is to prevent CM0,CM1 non-unified syntax
|
|
|
|
|
|
|
|
|
|
|
|
" loop%=:" "\n\t" |
|
|
|
|
|
|
|
|
|
|
|
/* bit 7 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#7,#1" "\n\t" /* Store read bit as the bit 7 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 6 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#6,#1" "\n\t" /* Store read bit as the bit 6 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 5 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#5,#1" "\n\t" /* Store read bit as the bit 5 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 4 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#4,#1" "\n\t" /* Store read bit as the bit 4 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 3 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#3,#1" "\n\t" /* Store read bit as the bit 3 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 2 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#2,#1" "\n\t" /* Store read bit as the bit 2 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 1 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#1,#1" "\n\t" /* Store read bit as the bit 1 */ |
|
|
|
|
|
|
|
|
|
|
|
/* bit 0 */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */ |
|
|
|
|
|
" ldr %[work],[%[bitband_miso_port]]" "\n\t" /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */ |
|
|
|
|
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */ |
|
|
|
|
|
" bfi %[bin],%[work],#0,#1" "\n\t" /* Store read bit as the bit 0 */ |
|
|
|
|
|
|
|
|
|
|
|
" subs %[todo],#1" "\n\t" /* Decrement count of pending words to send, update status */ |
|
|
|
|
|
" strb.w %[bin], [%[ptr]], #1" "\n\t" /* Store read value into buffer, increment buffer pointer */ |
|
|
|
|
|
" bne.n loop%=" "\n\t" /* Repeat until done */ |
|
|
|
|
|
|
|
|
|
|
|
: [ptr]"+r"(ptr), |
|
|
|
|
|
[todo]"+r"(todo), |
|
|
|
|
|
[bin]"+r"(bin), |
|
|
|
|
|
[work]"+r"(work) |
|
|
|
|
|
: [bitband_miso_port]"r"( BITBAND_MISO_PORT ), |
|
|
|
|
|
[sck_mask]"r"( SCK_MASK ), |
|
|
|
|
|
[sck_port]"r"( SCK_PORT_PLUS30 ) |
|
|
|
|
|
: "cc" |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void spiTxBlockX(const uint8_t* buf, uint32_t todo) { |
|
|
|
|
|
do { |
|
|
|
|
|
(void) spiTransferTx(*buf++); |
|
|
|
|
|
} while (--todo); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void spiRxBlockX(uint8_t* buf, uint32_t todo) { |
|
|
|
|
|
do { |
|
|
|
|
|
*buf++ = spiTransferRx(0xff); |
|
|
|
|
|
} while (--todo); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Pointers to generic functions for block tranfers
|
|
|
|
|
|
static pfnSpiTxBlock spiTxBlock = spiTxBlockX; |
|
|
|
|
|
static pfnSpiRxBlock spiRxBlock = spiRxBlockX; |
|
|
|
|
|
|
|
|
void spiBegin() { |
|
|
void spiBegin() { |
|
|
SET_OUTPUT(SS_PIN); |
|
|
SET_OUTPUT(SS_PIN); |
|
|
WRITE(SS_PIN, HIGH); |
|
|
WRITE(SS_PIN, HIGH); |
|
@ -329,6 +501,38 @@ |
|
|
SET_OUTPUT(MOSI_PIN); |
|
|
SET_OUTPUT(MOSI_PIN); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint8_t spiRec() { |
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
WRITE(MOSI_PIN, 1); /* Output 1s 1*/ |
|
|
|
|
|
uint8_t b = spiTransferRx(0xFF); |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
return b; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void spiRead(uint8_t* buf, uint16_t nbyte) { |
|
|
|
|
|
uint32_t todo = nbyte; |
|
|
|
|
|
if (todo == 0) return; |
|
|
|
|
|
|
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
WRITE(MOSI_PIN, 1); /* Output 1s 1*/ |
|
|
|
|
|
spiRxBlock(buf,nbyte); |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void spiSend(uint8_t b) { |
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
(void) spiTransferTx(b); |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void spiSendBlock(uint8_t token, const uint8_t* buf) { |
|
|
|
|
|
|
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
(void) spiTransferTx(token); |
|
|
|
|
|
spiTxBlock(buf,512); |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/**
|
|
|
/**
|
|
|
* spiRate should be |
|
|
* spiRate should be |
|
|
* 0 : 8 - 10 MHz |
|
|
* 0 : 8 - 10 MHz |
|
@ -344,15 +548,21 @@ |
|
|
case 0: |
|
|
case 0: |
|
|
spiTransferTx = spiTransferTx0; |
|
|
spiTransferTx = spiTransferTx0; |
|
|
spiTransferRx = spiTransferRx0; |
|
|
spiTransferRx = spiTransferRx0; |
|
|
|
|
|
spiTxBlock = spiTxBlock0; |
|
|
|
|
|
spiRxBlock = spiRxBlock0; |
|
|
break; |
|
|
break; |
|
|
case 1: |
|
|
case 1: |
|
|
spiTransferTx = spiTransfer1; |
|
|
spiTransferTx = spiTransfer1; |
|
|
spiTransferRx = spiTransfer1; |
|
|
spiTransferRx = spiTransfer1; |
|
|
|
|
|
spiTxBlock = spiTxBlockX; |
|
|
|
|
|
spiRxBlock = spiRxBlockX; |
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
spiDelayCyclesX4 = (F_CPU/1000000) >> (6 - spiRate); |
|
|
spiDelayCyclesX4 = (F_CPU/1000000) >> (6 - spiRate); |
|
|
spiTransferTx = spiTransferX; |
|
|
spiTransferTx = spiTransferX; |
|
|
spiTransferRx = spiTransferX; |
|
|
spiTransferRx = spiTransferX; |
|
|
|
|
|
spiTxBlock = spiTxBlockX; |
|
|
|
|
|
spiRxBlock = spiRxBlockX; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -361,41 +571,6 @@ |
|
|
WRITE(SCK_PIN, LOW); |
|
|
WRITE(SCK_PIN, LOW); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
uint8_t spiRec() { |
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
WRITE(MOSI_PIN, 1); /* Output 1s 1*/ |
|
|
|
|
|
uint8_t b = spiTransferRx(0xFF); |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
return b; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void spiRead(uint8_t* buf, uint16_t nbyte) { |
|
|
|
|
|
if (nbyte == 0) return; |
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
WRITE(MOSI_PIN, 1); /* Output 1s 1*/ |
|
|
|
|
|
for (int i = 0; i < nbyte; i++) { |
|
|
|
|
|
buf[i] = spiTransferRx(0xff); |
|
|
|
|
|
} |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void spiSend(uint8_t b) { |
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
(void) spiTransferTx(b); |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void spiSendBlock(uint8_t token, const uint8_t* buf) { |
|
|
|
|
|
|
|
|
|
|
|
WRITE(SS_PIN, LOW); |
|
|
|
|
|
(void) spiTransferTx(token); |
|
|
|
|
|
|
|
|
|
|
|
for (uint16_t i = 0; i < 512; i++) { |
|
|
|
|
|
(void) spiTransferTx(buf[i]); |
|
|
|
|
|
} |
|
|
|
|
|
WRITE(SS_PIN, HIGH); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#pragma GCC reset_options |
|
|
#pragma GCC reset_options |
|
|
|
|
|
|
|
|
#else |
|
|
#else |
|
|