필자는 Verilog에 SPI 슬레이브를 작성했다. 거기에 몇 가지 구현이 있지만, 나는 아직도 Verilog 및 디지털 논리를 일반적으로 배우기 때문에, 나는 스스로 작성하려고 노력하기로 결정했습니다.사양을 따르면 SPI 슬레이브가 작동하지 않습니까?
내 구현이 작동합니다. 그러나 그것을 작동시키기 위해서는 변화를 만들어야하고, 변화를 만들어 내 구현은 모토로라 SPI 스펙과 확연히 다릅니다. 나는 이것이 이상하다고 생각하는 것이 옳은가, 아니면 무언가가 어떻게 작동 하는지를 이해할 수 없는가?
SPI 신호는 SCK, SS, MOSI 및 MISO라는 네 개의 와이어로 들어옵니다. 놀랍지도 않습니다. FPGA는 12MHz에서 실행 중이며 SPI 버스는 1MHz에서 실행 중입니다. 전략은 모든 FPGA 클록 posedge에서 버스 SPI 버스를 샘플링하고 SCK 및 SS의 현재 값과 마지막 값을 추적하여 에지를 감지 할 수 있도록하는 것입니다. 또한 각 신호를 버퍼 reg를 통해 전달합니다. 따라서 로직은 항상 실제 이벤트 뒤에 두 개의 FPGA 클럭을 작동시킵니다. 클럭 1에서 버퍼에 신호를 래치합니다. 시계 2에서 논리에 사용하는 reg에 복사하고 시계 3에 적용합니다.
I 모드 0에서, SPI는 사양에 따라 SPI 모드 0을 사용하고, 슬레이브해야 샘플 SCK의 posedge에 MOSI 라인 SCK의 negedge에 다음 송신.
reg [511:0] data; // I exchange 512-bit messages with the master.
reg [2:0] SCK_buffer = 0;
always @(posedge clock) begin // clock is my FPGA clock
SCK_buffer <= {SCK_buffer[1:0], SCK};
end
wire SCK_posedge = SCK_buffer[2:1] == 2'b01;
wire SCK_negedge = SCK_buffer[2:1] == 2'b10;
reg [2:0] SS_buffer = 0;
always @(posedge clock) begin
SS_buffer <= {SS_buffer[1:0], SS};
end
wire SS_posedge = SS_buffer[2:1] == 2'b01;
wire SS_negedge = SS_buffer[2:1] == 2'b10;
wire SS_active = ~SS_buffer[1];
reg [1:0] MOSI_buffer = 0;
always @(posedge clock) begin
MOSI_buffer = {MOSI_buffer[0], MOSI};
end
wire MOSI_in = MOSI_buffer[1];
assign MISO = data[511];
always @(posedge clock) begin
if (SS_active) begin
if (SCK_posedge) begin
// Clock goes high: capture one bit from MOSI.
MOSI_capture <= MOSI_in;
end
else if (SCK_negedge) begin
// Shift the captured MOSI bit into the LSB of data and output
// the MSB from data. Note: MISO is a wire that outputs data[511].
data <= {data[510:0], MOSI_capture};
end
end
end
이 코드는 다음과 같이 작동합니다 :
그래서 나는 그것을 바로 그런 식으로 쓴- SS 활성 (낮음), 데이터를 간다 [511] MISO에 출력에 의해 이미 철사의 미덕. (버스에서 유일하기 때문에 여기에 트라이 스테이트가 없습니다.)
- SCK의 posedge에서 슬레이브는 MOSI를 샘플링하고 마스터는 MISO에서 데이터 [511]를 가져옵니다.
- 슬레이브는 SCK를 무시할 때 MOSI에서 샘플링 된 비트를 데이터로 이동시켜 새로운 비트를 MISO 출력 위치로 이동시킵니다.
이 버전을 실행하면 모든 곳의 비트가 떨어졌습니다. 문자 그대로 마스터에서 슬레이브로 보낸 512 비트 메시지의 절반이 손상되었습니다.
오픈 소스 SPI 슬레이브 구현을 살펴본 결과, SCK의 부정 사용을 사용하지 않았다는 사실을 알게되었습니다. 그래서 나는이 내 코드를 변경 :
always @(posedge clock) begin
if (SS_active) begin
if (SCK_posedge) begin
// Skip that "capture" business and just shift MOSI right into the
// data reg.
data <= {data[510:0], MOSI_in};
end
end
end
이 변경 한 후 완벽하게
을했다. 완전 방탄. 하지만 생각하고 있니?
나는 괜찮습니다. MISO는 SCK의 포지 션 직후에 새로운 가치를 얻습니다. 마스터가 샘플을 샘플링하면 다음 위치에 계속 머물러 있습니다. 그러나 무시 무시한 부분에서 잘못 표시된 부분을 변경하는 것이 잘못된 이유는 무엇입니까? 버퍼링으로 인해 SPI 버스 뒤에서 두 FPGA 사이클을 실행한다고해도 SCK의 1 틱마다 12 개의 FPGA 클록이 남아 있기 때문에 SCK 무시와 다음 포즈 사이에 여섯 개의 FPGA 사이클이 있음을 의미합니다. 시간에 맞춰 미코에 비트를 낼 수 있어야합니다.
실제 (SCI 모드 0의) 모든 사람들이 SCK 포즈를 취한 직후 MISO를 업데이트하고 무시할 것에 대해 걱정하지 않습니까?
감사합니다.
나는 "MOSI는 SCK의 기세가 된 직후에 새로운 가치를 얻는다"라고 썼다. "* MISO * gets ..."라고 써야했을 때 –
"일반적인 생각은 읽은 샘플 데이터를 생성 한 다른 클럭 에지에서 ... "나는 완전히 동의하고 이것이 내 첫 구현이 어떻게 작동했는지를 설명한다. SCK negedge에 대한 데이터를 생성한다. negedge를 감지), 주인은 posedge에 샘플을 표시합니다. 하지만 그건 효과가 없었습니다. posedge를 감지 한 직후에 데이터를 생성하도록 코드를 변경했을 때만 작동했습니다. –
"SCK 및 MOSI (및 SS)에서 별도의 동기화 프로그램을 사용한다는 것이 문제"라는 말의 의미를 설명 할 수 있습니까? 어떻게 그들을 하나로 결합시킬 수 있을까요? –