2012-03-26 4 views
4

stm32f4에서 i2c 슬레이브 수신기 인터럽트 서비스 루틴을 구현하려고합니다. 여기 내 똑똑한 코드가 있습니다.stm32f4의 I2C 슬레이브 수신기

void I2C2_EV_IRQHandler() 
    { 
    switch (I2C_GetLastEvent(I2C2)) 
    { 
    //The address sent by the master matches the own address of the peripheral 
    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: 
     //The slave stretches SCL low until ADDR is 
     //cleared and DR filled with the data to be sent 
     I2C_ClearFlag(I2C2,I2C_FLAG_ADDR); 
     break; 

    //The application is expecting a data byte to be received 
    case I2C_EVENT_SLAVE_BYTE_RECEIVED: 
     I2C_ReceiveData(I2C2); 
     break; 

    //The application is expecting the end of the communication 
    //Make sure that both ADDR and STOPF flags are cleared 
    //if both are found set. 
    case I2C_EVENT_SLAVE_STOP_DETECTED: 
     if(I2C_GetFlagStatus(I2C2,I2C_FLAG_ADDR) == SET) 
      I2C_ClearFlag(I2C2,I2C_FLAG_ADDR); 
     if(I2C_GetFlagStatus(I2C2,I2C_FLAG_STOPF) == SET) 
      I2C_ClearFlag(I2C2,I2C_FLAG_STOPF); 
} 

}

인터럽트 호출되고 I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED 경우가 입력된다. SCL이 낮습니다. 레퍼런스 매뉴얼에 따르면 주소 플래그를 지우면 시계가 계속되고 데이터가 전송됩니다 (페이지 579 - 슬레이브 수신기). 내 생각에 인터럽트는 데이터가 도착하고 다음 상태가 I2C_EVENT_SLAVE_BYTE_RECEIVED가되면 항상 호출됩니다.

stm 또는 google을 통해 예제를 찾을 수 없습니다. 아무도 나를 도우 실례를 보여 줄 수 없습니까?

+0

위의 코드에서 하나의 오류는 각각의 경우에 누락 된 확인입니다. 내 경우에는 마스터와 통신하는 다른 노예도 있습니다. 그래서 내 노예를 초기화 한 후 버스에서 들으십시오. 내 커뮤니케이션의 일부가 아닌 스톱 비트를받습니다. 그래서 정지 비트를 삭제할 수 없습니다. 또한 ADDR 플래그를 재설정하는 것은 생각만큼 쉽지 않습니다. –

답변

2

이제는 작동합니다. 내 문제는 ADDR 및 STOPF 레지스터를 참조 설명서에서 지정된 명령으로 다시 설정할 수 없다는 것이 었습니다. 그러나 그것이 반복되면 그것은 나를 위해 잘 작동합니다. 여기 내 인터럽트 루틴.

void I2C3_EV_IRQHandler() 
{ 
    switch (I2C_GetLastEvent(I2C3)) 
    { 

    case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: 
     STM_EVAL_LEDOn(LED3); 
     STM_EVAL_LEDOff(LED5); 
     break; 

    case I2C_EVENT_SLAVE_BYTE_RECEIVED: 
     STM_EVAL_LEDToggle(LED4); 
     STM_EVAL_LEDOff(LED3); 
     I2C_InputBuffer[I2C_InputBufferIndex++] = I2C_ReceiveData(I2C3); 
     break; 

    case I2C_EVENT_SLAVE_STOP_DETECTED: 
     STM_EVAL_LEDOn(LED6); 
     STM_EVAL_LEDOff(LED4); 
     break; 
    } 

    I2C_CleanADDRandSTOPF(); 

    if(I2C_InputBufferIndex > MOTOR_PACKAGE_SIZE-1) 
    { 
     motorHandleEvent(I2C_InputBuffer); 
     I2C_InputBufferIndex = 0; 
     uint8_t resetIndex; 
     for(resetIndex = 0; resetIndex < MOTOR_PACKAGE_SIZE; resetIndex ++) 
     I2C_InputBuffer[resetIndex] = 0; 
    } 
} 

inline void I2C_CleanADDRandSTOPF() 
{ 
    while ((I2C3->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR) 
    { 
    volatile uint32_t temp; 
    temp=I2C3->SR1; 
    temp=I2C3->SR2; 
    } 
    while ((I2C3->SR1&I2C_SR1_STOPF) == I2C_SR1_STOPF) 
    { 
    volatile uint32_t temp; 
    temp=I2C3->SR1; 
    I2C3->CR1 |= 0x1; 
    } 
} 
0

하드웨어가 슬레이브가 마스터를 따라갈 수 있도록 시계를 늘리고 있습니다. 슬레이브는 먼저 주소 일치를 기다립니다. 그러면 SCL이 로우로 유지되는 동안 인터럽트가 발생합니다. 이것은 슬레이브가 기본적으로 마스터에 흐름 제어를 제공 할 수있게합니다. 마스터는 SCL이 슬레이브에 의해 로우로 유지되는 것을 감지하고 마스터가 더 이상의 데이터를 보내기 전에 SCL이 해제 될 때까지 기다립니다. 따라서 SCL을 하이 상태로 만들 때까지 마스터가 더 이상 데이터를 전송하지 않기 때문에 데이터 수신에 대한 추가 인터럽트를 얻지 못합니다. 여기에서 시계의 길이를 읽을 수 있습니다 http://en.wikipedia.org/wiki/I%C2%B2C

+0

H TJD 답변 해 주셔서 감사합니다. 하지만 내 추천서에서 언급했듯이, ADDR 레지스터가 읽혀 비어있게 될 때까지는 슬레이브가 SCL을 로우로 유지했다. 그게 문제가 아니야이 경우 –

+0

나는 당신의 실제 질문이 무엇인지 혼란 스럽다. – TJD