I2C PIC Slave/Master Code

Beste leden,

Ik zit nu reeds een paar dagen te sukkelen met de I2C code van mijn PIC's
(PIC18F46K40/PIC18F26K40)
Ik gebruik 2 PIC's waarvan 1 slave is en de andere Master.

Nu loopt de code vlot van master naar slave en de slave voert mooi het comando uit.
Maar als ik een read wil doen dan loopt de code in de slave om de een of andere reden vast en zit de Master te wachten op een release van de SDA lijn (of zo lijkt het toch)

Iemand enig idee waar mijn fout zit?
Mijn code onderstaande.

Hier een foto van de I2C bus 'foutcode':
https://i.ibb.co/3fqZV0b/Knipsel.png
(D1 is SCL D2 is SDA)

Slave Code:
https://pastebin.com/temmEiBB

MAster Code:
https://pastebin.com/5Z7qXW0B

Code is alleen toegankelijk na inloggen. Daar begin ik niet aan.

Damn the torpedoes, full speed ahead!

Op 22 april 2020 11:02:50 schreef Hunter:
Code is alleen toegankelijk na inloggen. Daar begin ik niet aan.

Mijn fout, is aangepast, bedankt op het te melden!

Dat is best wel lastig om goed te krijgen.

De master moet tegen de slave vertellen dat het bericht afgelopen is door op het laatste databyte geen ACK terug te sturen.

En de slave moet data in het transmit register blijven sturen net zolang totdat de master einde bericht aangeeft. Als er geen data is dan best 0xFF, want daarmee wordt SDA hoog en kan de master een stop signaal genereren.

BEdankt voor je antwoord,

Ik denk dat mijn fout ergens in dit stuk van de (slave) code zit:

ik verwacht max 2 reads achter elkaar in het commando dus ook niet meer opgenomen dan dat.
mis ik soms ergens een wachttijd?

c code:

else if(!SSP1STATbits.D_nA && SSP1STATbits.R_nW) //If last byte was Address + Read
  {    
    SSP1IF = 0;
    retVal = SSP1BUF;
    while(BF1);
    SSP1BUF = _data ;
    CKP1 = 1;
    SSP1IF = 0;
    SSP1IF = 0;
    if(ACKSTAT1)
    {        
        SSP1BUF = _data ;
        CKP1 = 1;
        SSP1IF = 0;
    }
    CKP1 = 1;
    SSP1IF = 0;

Ik weet niks van PICs, maar wel van I2C.

De master genereert de clocks, en de Slave gerereert de data tijdens een read.

De hardware transmitter in de slave moet weten dat het bericht is afgelopen. En dat moet door de master worden aangegeven dmv een NAK op het laatste byte.

Als de slave al eerder stopt met data terug sturen, dan gaat de Slave hardware de SCL lijn blokkeren (clock stretching) totdat de slave applikatie nieuwe data aanlevert. En als die nieuwe dan een 0x00 is dan trekt de Slave SDA naar beneden totdat er 8 klokpulsen van de master binnenkomen.

In beide gevallen kan de master geen STOP genereren.

Dus het probleem zit in de slave (Die moet 0xFF blijven sturen totdat er een STOP binnenkomt of een NAK)

En het zit ook in de master want die moet een NAK terugsturen op het laatste byte.

Arco

Special Member

Ik gebruik altijd de SSP interrupt (SSPxIE/SSPxIF) voor ontvangst, da's wat frisser... (altijd 1 byte die je kunt verwerken)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com

Op 22 april 2020 12:24:07 schreef Arco:
Ik gebruik altijd de SSP interrupt (SSPxIE/SSPxIF) voor ontvangst, da's wat frisser... (altijd 1 byte die je kunt verwerken)

Hoe hou je dan bij welke data er dan verwerkt moet worden? pointer, tabel?

Arco

Special Member

Je moet het SSPxSTAT:D/A bit bekijken bij een interrupt.

Is dit '0', dan is de byte een adres
Is dit '1', dan is het data die verwerkt moet worden.
Tellertje bijhouden en ophogen na iedere databyte. Na ontvangst adres byte tellertje weer op '0'

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com