Estoy tratando de hacer que un chip ARM LPC2132 y un Altera Cyclone FPGA se comuniquen utilizando el protocolo SPI. Específicamente, tengo el tablero Saxo-L de KNJN, que tiene las señales precableadas entre los dos tableros, pero No puedo hacer que los dos chips hablen.
La documentación proporciona ejemplos de código, pero no estoy teniendo suerte con estos. ¿Alguien puede compartir cómo hacer que estos dos chips hablen?
Aquí está la fuente que estoy usando:
Código ARM:
// SPI master using SPI1/SSP
// (c) KNJN LLC 2007, 2008
// Tested with LPC ARM on Saxo-L (CPOL=0, CPHA=1, MSB first, SSEL controlled through GPIO)
#include "lpc23xx.h"
void SSP_init()
{
SSP0CPSR = 0x02; // SSP max speed
SSP0CR0 = 0x87; // SSP max speed, 8 bits, CPHA=1
SSP0CR1 = 0x02; // SSP master mode
PINSEL1 = 0x0A8; // SPI mode for pins P0.17 to P0.19, while P0.20 (SSEL) stays as GPIO
IOSET0 = 0x00100000; // SSEL inactive (up)
}
void SSP_send_recv(char* ob, int len_ob, char* ib, int len_ib)
{
// before doing anything, let's make sure the SSP receive FIFO is empty (by reading data out of it if necessary)
while(SSP0SR & 0x04) SSP0DR;
IOCLR0 = 0x00100000; // SSEL active (down)
while(len_ob || len_ib)
{
if(len_ob && (SSP0SR & 0x02))
{
SSP0DR=*ob++;
len_ob--;
}
if(len_ib && (SSP0SR & 0x04))
{
*ib++=SSP0DR;
len_ib--;
}
}
IOSET0 = 0x00100000; // SSEL inactive (up)
}
void SSP_send_only(char* ob, int len)
{
IOCLR0 = 0x00100000; // SSEL active (down)
while(len) if(SSP0SR & 0x02) { SSP0DR=*ob++; len--; } // transmit
while(!(SSP0SR & 0x11)); // wait until transmission is completed
while(SSP0SR & 0x04) SSP0DR; // empty the receive FIFO
IOSET0 = 0x00100000; // SSEL inactive (up)
}
int main(void)
{
char bufo[2] = {0x55, 0x54};
char bufi[2];
SSP_init();
IODIR0 = 0x80100000; // turn on LED driver (P0.31) and P0.20 (SSEL)
while(1)
{
SSP_send_recv(bufo, sizeof(bufo), bufi, sizeof(bufo));
if(((bufi[0]+bufi[1])
&0xFF)==254)
IOSET0 = 0x80000000;
else
IOCLR0 = 0x80000000;
}
return(0);
}
Asamblea ARM:
/*
* Some defines for the program status registers
*/
ARM_MODE_USER = 0x10 /* Normal User Mode */
ARM_MODE_FIQ = 0x11 /* FIQ Fast Interrupts Mode */
ARM_MODE_IRQ = 0x12 /* IRQ Standard Interrupts Mode */
ARM_MODE_SVC = 0x13 /* Supervisor Interrupts Mode */
ARM_MODE_ABORT = 0x17 /* Abort Processing memory Faults Mode */
ARM_MODE_UNDEF = 0x1B /* Undefined Instructions Mode */
ARM_MODE_SYS = 0x1F /* System Running in Priviledged Operating Mode */
ARM_MODE_MASK = 0x1F
I_BIT = 0x80 /* disable IRQ when I bit is set */
F_BIT = 0x40 /* disable IRQ when I bit is set */
/*
* Register Base Address
*/
.section .vectors,"ax"
.code 32
/****************************************************************************/
/* Vector table and reset entry */
/****************************************************************************/
_vectors:
ldr pc, ResetAddr /* Reset */
ldr pc, UndefAddr /* Undefined instruction */
ldr pc, SWIAddr /* Software interrupt */
ldr pc, PAbortAddr /* Prefetch abort */
ldr pc, DAbortAddr /* Data abort */
ldr pc, ReservedAddr /* Reserved */
ldr pc, IRQAddr /* IRQ interrupt */
ldr pc, FIQAddr /* FIQ interrupt */
ResetAddr: .word ResetHandler
UndefAddr: .word UndefHandler
SWIAddr: .word SWIHandler
PAbortAddr: .word PAbortHandler
DAbortAddr: .word DAbortHandler
ReservedAddr: .word 0
IRQAddr: .word IRQHandler
FIQAddr: .word FIQHandler
.ltorg
.section .init, "ax"
.code 32
.global ResetHandler
.global ExitFunction
.extern main
/****************************************************************************/
/* Reset handler */
/****************************************************************************/
ResetHandler:
/*
* Wait for a stable oscillator
*/
nop
nop
nop
nop
nop
nop
nop
nop
/*
* Setup a stack for each mode
*/
msr CPSR_c, #ARM_MODE_UNDEF | I_BIT | F_BIT /* Undefined Instruction Mode */
ldr sp, =__stack_und_end
msr CPSR_c, #ARM_MODE_ABORT | I_BIT | F_BIT /* Abort Mode */
ldr sp, =__stack_abt_end
msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT /* FIQ Mode */
ldr sp, =__stack_fiq_end
msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT /* IRQ Mode */
ldr sp, =__stack_irq_end
msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT /* Supervisor Mode */
ldr sp, =__stack_svc_end
/*
* Copy initialized variables .data section (copy from flash to RAM)
*/
ldr r1, =etext
ldr r2, =__data_start
ldr r3, =__data_end
data_copy_loop:
cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo data_copy_loop
/*
* Clear .bss section
*/
ldr r1, =__bss_start
ldr r2, =__bss_end
ldr r3, =0
bss_clear_loop:
cmp r1, r2
strlo r3, [r1], #+4
blo bss_clear_loop
/*
* Jump to main
*/
mrs r0, cpsr
bic r0, r0, #I_BIT | F_BIT /* Enable FIQ and IRQ interrupt */
msr cpsr, r0
mov r0, #0 /* No arguments */
mov r1, #0 /* No arguments */
ldr r2, =main
mov lr, pc
bx r2 /* And jump... */
ExitFunction:
nop
nop
nop
b ExitFunction
/****************************************************************************/
/* Default interrupt handler */
/****************************************************************************/
UndefHandler:
b UndefHandler
SWIHandler:
b SWIHandler
PAbortHandler:
b PAbortHandler
DAbortHandler:
b DAbortHandler
IRQHandler:
b IRQHandler
FIQHandler:
b FIQHandler
.weak ExitFunction
.weak UndefHandler, PAbortHandler, DAbortHandler
.weak IRQHandler, FIQHandler
.ltorg
/*** EOF ***/
Código Verilog:
// SPI slave
// (c) KNJN LLC 2007, 2008
// Configures the LPC ARM with CPOL=0, CPHA=0/1, MSB first
/////////////////////////////////
module SPI_slave(clk, SCK, MOSI, MISO, SSEL, LED);
input clk;
input SCK, MOSI, SSEL;
output MISO;
output LED;
/////////////////////////////////
reg [2:0] SCKr; always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
wire SCK_risingedge = (SCKr[2:1]==2'b01);
wire SCK_fallingedge = (SCKr[2:1]==2'b10);
reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
wire SSEL_active = ~SSELr[1]; // SSEL is active low
wire SSEL_startmessage = (SSELr[2:1]==2'b10); // message starts at falling edge
wire SSEL_endmessage = (SSELr[2:1]==2'b01); // message stops at rising edge
reg [1:0] MOSIr; always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
wire MOSI_data = MOSIr[1];
/////////////////////////////////
reg [2:0] bitcnt;
reg byte_received;
reg [7:0] byte_data_received;
always @(posedge clk)
begin
if(~SSEL_active)
bitcnt <= 3'b000;
else
if(SCK_risingedge)
begin
bitcnt <= bitcnt + 3'b001;
byte_data_received <= {byte_data_received[6:0], MOSI_data};
end
end
always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111);
/////////////////////////////////
//assign MISO = 1'b0;
reg [7:0] byte_data_sent;
reg [7:0] cnt;
always @(posedge clk) if(SSEL_startmessage) cnt<=cnt+8'h1; // count the messages
always @(posedge clk)
if(SSEL_active)
begin
if(SSEL_startmessage)
byte_data_sent <= cnt;
else
if(SCK_fallingedge)
begin
if(bitcnt==3'b000)
byte_data_sent <= ~cnt;
else
byte_data_sent <= {byte_data_sent[6:0], 1'b0};
end
end
assign MISO = byte_data_sent[7]; // we assume that there is only one slave on the SPI bus, so we don't bother with a tri-state buffer there
// otherwise we would need to tri-state MISO when SSEL is inactive
/////////////////////////////////
reg LED;
always @(posedge clk) if(byte_received) LED <= byte_data_received[0];
endmodule