2017-04-04 5 views
1

우리는 atmel atmega328 MCU를 사용하여 다른 IC와 통신하기 위해 SPI를 사용하려고합니다. 대상 IC는 명령 (코드의 헤더)을 가져온 다음 요청 된 레지스터에 저장된 정보를 다시 제공합니다 (또는 명령이 쓰기 인 경우 해당 주소에 씁니다). 그러나, 우리는 여기에 두 가지 문제가 발생하는 :atmega328의 SPI가 작동하지 않습니다.

  1. 아무것도 SPI에서 온다, 유일한 변화는 (우리가 제어하는)가 CS 라인에 있습니다. SPI 클럭 없음, 데이터 라인에 데이터 없음.

  2. 헤더를 쓸 때 for 루프의 첫 번째 반복은 프로그램이 while 루프에 들어 가지 않습니다 (포트 6의 LED는 켜지지 않음).

아래의 코드는 도움이 될 것입니다.

#define DDR_SPI DDRB 
#define DD_MISO DDB4 
#define DD_MOSI DDB3 
#define DD_SCK DDB5 
#define DD_SS DDB6 

void SPI_MasterInit(void) 
{ 
    /* Set MOSI, SCK and CS output, all others input */ 
    DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS); 
    /* Enable SPI, Master, set clock rate = System clock/16 */ 
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); 
} 

int readfromspilow(uint16 headerLength, const uint8 *headerBuffer, uint32 readLength, uint8 *readBuffer) 
{ 


    PORTB &= ~(1 << PORTB6);    // Set CS low 

    for(int i=0; i<headerLength; i++) 
    { 
     SPDR = headerBuffer[i];    //Send entry i of the header to the spi register 
     sleep_us(5);      // Give the flag time to reset, might be unnecessary 
     PORTD |= (1 << PORTD5);    //LED for diagnostics 
     while(!(SPSR & (1<<SPIF))){   //Wait for SPIFinished flag 
      PORTD |= (1 << PORTD6);   //LED for diagnostics 
     } 

     PORTD &= ~(1 << PORTD3);   //LED for diagnostics 



     //readBuffer[0] = SPDR; // Dummy read as we write the header 
    } 

    for(int i=0; i<readLength; i++) 
    { 
     SPDR = 0xFF;      // Dummy write as we read the message body 
     sleep_us(5);      // Give the flag time to reset, might be unnecessary 
     while(!(SPSR & (1<<SPIF)));   //Wait for SPIFinished flag 
     readBuffer[i] = SPDR ;    //Store the value in the buffer 
    } 

    PORTB |= (1 << PORTB6);     // Set CS high 


    return; 
} 

편집 : 초기화

+0

나중에 코드를 어떻게 사용합니까? DDR_SPI 및 기타는 무엇입니까? 비트가 일치합니까? while 루프는 SPI가 끝나기를 기다리는 동안 멈 춥니 다? – tilz0R

+0

우리는 단순히 필요한 명령을 헤더 (주소와 우리가 읽고 자하는 레지스터에 대한 것)와 예상되는 응답의 길이와 함께 readfromspilow를 읽기 길이로, 버퍼가 읽기 대답을 저장하는 지점으로 호출합니다. SPI에 대한 정의를 편집과 함께 추가했는데, "비트 일치"란 무엇을 의미하는지 확신 할 수 없습니다. while은 첫 번째 반복을 건너 뜁니다 (이유는 알지 못합니다). 그러나 다음 iteration에 걸렸습니다 (아마도 SPI가 신호를 보내지 않았기 때문일 수 있습니다) – Sebastian

답변

1

귀하의 코드에 대한 추가되었습니다 정의는 올바른 것 같다,하지만 당신은 SPI 인터럽트 핸들러를 사용하지 않는 때문에, 당신은 전에 SPSR의 SPIF 비트를 지워야합니다 당신은 SPDR을 통해 데이터를 보내고 있습니다. SPDR은 SPIF 플래그가 설정된 데이터를 허용하지 않습니다.

1

는 수동 19.5.2 대안

따르면, SPIF 비트 먼저 SPI 데이터 레지스터 (SPDR)에 액세스 한 후, SPIF 세트와 SPI 상태 레지스터를 판독함으로써 소거된다.

코드에서이 작업을 수행하지 않으므로 결코 지워지지 않는 플래그가 설정되어있을 수 있습니다. 에 코드를 변경하려고 : 우리는 그것을 해결

volatile uint8_t spsr = SPSR;  //Dummy-read the flag register to clear flags 
SPDR = headerBuffer[i];    //Send entry i of the header to the spi register 
PORTD |= (1 << PORTD5);    //LED for diagnostics 
while(!(SPSR & (1<<SPIF))){   //Wait for SPIFinished flag 
    PORTD |= (1 << PORTD6);   //LED for diagnostics 
} 
0

을, 문제는 그렇지 않으면 MCU가 슬레이브 동작 모드의 경우에 변경할 수 있습니다, 포트 B2 필요의 기본 SS는 초기화 단계에서 출력으로 정의하는 것이 었습니다 핀은 떠있는 채로 있습니다. 이것은 SPIF-flag를 매번 발생시킬 때마다 1로 설정하여 우리의 수표를 엉망으로 만든다.