2013-08-13 1 views
1

필자는 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 

이 코드는 다음과 같이 작동합니다 :

그래서 나는 그것을 바로 그런 식으로 쓴

  1. SS 활성 (낮음), 데이터를 간다 [511] MISO에 출력에 의해 이미 철사의 미덕. (버스에서 유일하기 때문에 여기에 트라이 스테이트가 없습니다.)
  2. SCK의 posedge에서 슬레이브는 MOSI를 샘플링하고 마스터는 MISO에서 데이터 [511]를 가져옵니다.
  3. 슬레이브는 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를 업데이트하고 무시할 것에 대해 걱정하지 않습니까?

감사합니다.

답변

2

나는 주인이하고있는 일에 대해 정확히 혼란 스러울 수 있습니다. 당신은 이라고 말합니다. MOSI는 SCK의 포지 션 직후에 새로운 가치를 얻었고 마스터는 다음 샘플을으로 샘플링했습니다. 아마도 슬레이브 샘플을 샘플링하지만, 일반적으로 독자는 데이터를 생성 한 클럭 에지 인 클럭 에지에서 샘플을 샘플링하여 설정 및 유지를 최대화 할 수 있습니다. 나는 당신의 경우 마스터가 상승 에지가 아닌 SCK의 하강 에지에서 데이터를 생성해야한다고 생각한다.

어쨌든 가장 먼저해야 할 일은 마스터 디바이스의 데이터 시트를 얻고 그 디바이스의 의도를 파악하는 것입니다. 이상적으로 SCLK, MOSI 및 SS에 대한 스코프를 가져 와서 실제 마스터 타이밍이 무엇인지 찾아야합니다. 마스터가 MOSI를 변경하는시기와 MOSI 설정 및 SCLK 에지 (pos 또는 neg)에 대한 내용을 확인하십시오.

코드는 실제로 SCK 상승 에지에서 MOSI를 샘플링하지 않으며 두 번째 버전은 하강 에지에서 샘플링하지 않습니다. 그것은 가장자리 근처 어딘가에서 샘플링합니다. 문제는 SCK 및 MOSI (및 SS)에서 별도의 동기화 장치가 있다는 것입니다. 일반적으로 이것은 실패의 처방이지만 특정 타이밍에 따라 귀하의 경우에는 효과가있을 수도 있고 그렇지 않을 수도 있습니다. 이런 식으로 생각하십시오. 당신이 옳다면, "MOSI는 SCK의 포지셔닝 직후에 새로운 가치를 얻습니다."그런 다음 MOSI에 대한 긴 설정과 짧은 보류가 있으며, 높은 가치를 보았을 때 샘플링이 실패합니다 SCK에서 (실제로 발생한 후 최대 84ns) MOSI가 변경되어 유효하지 않습니다.

올바른 방법은 SCK로 클록 된 F/F에서 MOSI (및 SS)를 샘플링하고 소형 디지털 PLL을 사용하여 SCK에 고정시켜 샘플러 출력을 읽을시기를 알 수 있도록하는 것입니다 . 타이밍을 이해하고 샘플링하는 모든 것을 거대한 설정으로 유지하고 있다면 SCK를 현재 샘플링 할 수 있습니다. 이 경우 MOSI 및 SS에서 동기화가 필요하지 않습니다. 안정화 된 신호를 샘플링 할 수있는 인 에이블 신호를 생성하십시오.

+0

나는 "MOSI는 SCK의 기세가 된 직후에 새로운 가치를 얻는다"라고 썼다. "* MISO * gets ..."라고 써야했을 때 –

+0

"일반적인 생각은 읽은 샘플 데이터를 생성 한 다른 클럭 에지에서 ... "나는 완전히 동의하고 이것이 내 첫 구현이 어떻게 작동했는지를 설명한다. SCK negedge에 대한 데이터를 생성한다. negedge를 감지), 주인은 posedge에 샘플을 표시합니다. 하지만 그건 효과가 없었습니다. posedge를 감지 한 직후에 데이터를 생성하도록 코드를 변경했을 때만 작동했습니다. –

+0

"SCK 및 MOSI (및 SS)에서 별도의 동기화 프로그램을 사용한다는 것이 문제"라는 말의 의미를 설명 할 수 있습니까? 어떻게 그들을 하나로 결합시킬 수 있을까요? –