avr uart met MAX485: send from slave to master ?

trix

Golden Member

goedendag,

zoals sommige van julie al weten ben ik bezig met een wat groter project, wat bestaat uit meerdere disiplines binnen C.

ik heb 1 master en 2 slaves (worden later meer slaves).
ik kan al vanuit de master de 2 slaves afzonderlijk aanroepen en er een byte naar toe sturen.
so far so good.
maar nu ben ik zover dat ik data v/d slave naar de master moet kunnen sturen, en dat schijnt niet zo moeilijk te zijn, maar na een dag proberen krijg ik het nog niet voor elkaar, en ik heb niet het idee dat ik het een en ander voldoende begrijp :( .

ik maak gebruik v/d MPCM mode, maar zover ik het begrijp, is dat enkel en alleen om de adresering v/d master naar de slave te verzorgen.

hoe ik het nu probeer:
1e - ik stuur van uit master naar de slave een verzoek: TSOP send your data to me.
2e - ik maak in de slave pin 2&3 v/d MAX485 hoog, (in zend mode)
3e - ik stuur van uit de slave een byte met:

c code:

while ((UCSRA & (1 << UDRE)) == 0) {}; // do nothing till the UDR is ready to receive
UDR = 0b10101010;

4e - in de master maak ik pin 2&3 laag (ontvangst mode)
5e - in de master lees ik de byte met:

c code:

while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
receivedbyte = UDR0; // Fetch the received byte value into the variable "ReceivedByte"
if (receivedbyte == 0b10101010)
{
PORTB |= (1 << PINB7); // LED = 1 just for checking GEEL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

maar bovenstaande werkt niet.
is er iemand die weet hoe je het best v/d slave naar de master data kan versturen ?
alvast, bedankt.

eigenwijs = ook wijs

Definieer eens "Het bovenste werkt niet".

Wat krijg je waar precies binnen? Of juist niet.

Het veneinige zit hem in het omschakelen van de transceivers in zend/ontvang modes.

Bij de zender moet je wachten tot alle bytes uit de buffer transmitted zijn en dan pas de zendlijn omschakelen in ontvang modes. Dat kun je dus niet doen als net het laatste byte in het TX register gestopt hebt.
Je moet dus eerst lezen of de transmitter empty is, dan direct het bitje omzetten naar ontvangst mode. (Zowel master als slave)

Dan nog wat: Je ontvangt dan misschien ook nog je eigen data terug tijdens het verzenden. Dat kun je op verschillende manieren oplossen.
Eentje is de receiver uitzetten tijdens het verzenden.
Een andere is in de interrupt handler van je receive de databytes wegmikken die je tijdens het verzenden ontvangt. (Je kunt ook checken of de bytes identiek zijn, heb je meteen een collision check)
Nog een andere is als je hardware daar support voor heeft, heb ik eigenlijk nooit bekeken op een AVR of dat kan.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

Zoals je het beschrijft kan het niet werken: je zegt dat je in de slave de byte stuurt en een stap verder schakel je de master pas op ontvangen.

Je moet beschrijven:

code:


 master:
    mijnmax = verzend;
    send_request_byte ();
    wacht_tot_verzonden ();
    turnaround: mijnmax = ontvangen 


  slave: 
    mijnmax = ontvangen 
    byte = ontvang_byte (); 
    if byte == REQUEST 
       turnaround: mijnmax = verzend;  

Verder zou ik even voor het debuggen kijken of je uberhaupt iets ontvangt.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
trix

Golden Member

werkt niet: de LED gaat gewoon niet branden.

mischien moet ik inderdaad checken of de buffers wel leeg zijn, voordat ik ze omschakel naar de zend/ontvangst mode.
dat terug echo-en heb ik niet gemerkt, ik zou ook niet weten hoe het eruit ziet.

ik ga morgen eens wat meer naar de timing kijken. en mischien een LA op de A&B lijn zetten om te kijken wat er precies gebeurt.

edit:
de timing van mijn stappenplan klopt inderdaad niet, morgen eens kijken of ik dat echt zo gemaakt heb,.....kijk nergens meer van op.

@rew: mijnmax = verzend/ontvangen daar bedoel je de MAX485 mee toch ?

eigenwijs = ook wijs

RS485 is lastig want half duplex.

Als je de receiver in de MAX485 uitzet dan wordt je RxD niet meer aangestuurd. En dan raakt je uart out of sync. Het is nog maar de vraag of die dan het startbit nog wel herkent

En als je de Transmitter te vroeg uitzet dan komt je data niet eens op de lijn.

Daar zijn meerdere oplossingen voor :
- Pullup weerstand op RxD van je Uart.
- Weerstanden op de bus die de bus in een bekende toestand (niveau van een stop bit) houden als de transmitters aan allebei de kanten uit staan.
- De transmitter moet wachten op TXC voordat die de transmitter op de MAX485 uitzet.
- De receiver kan best even wachten met een response om zeker te weten dat de transmitter aan de andere kant al heeft omgeschakeld.
- Alle berichten moeten best beginnen met 0xFF als eerste byte na het omschakelen van de richting. Dit geeft de andere kant tijd om te schakelen en dan komen de receivende uarts weer in sync.
- Je kunt beter je eigen receiver altijd aan laten staan. Dan kun je controleren of de data die je verstuurt ook echt op de lijn terecht komt.

fatbeard

Honourable Member

Bij RS485 (of elke andere half-duplex communicatie) kan het handig zijn om 'naar jezelf te luisteren', d.w.z. de ontvanger altijd aan te hebben. Als er dan op de ontvanger niet hetzelfde tevoorschijn komt als je verzendt is er sprake van een 'collission' of een kortsluiting in de lijn.
Voor een systeem met slechts één master en slaves die alleen praten als ze daar opdracht voor hebben gekregen is dat misschien niet nodig.

Wel is het aan te raden om de transmitter minimaal één bittijd voor het feitelijke verzenden te activeren, opdat het startbit correct geïnterpreteerd kan worden door de ontvanger. Een andere truuk hiervoor is het padden van de berichten met 0x00 of 0xff aan het begin, zodat UARTS zich kunnen 'inregelen'.

Het kan ook handig zijn om de lijn te biasen in de 'mark state', op die manier is het correct binnenkomen van het startbit gegarandeerd en kun je ook onderbrekingen detecteren.

Een goed begin is geen excuus voor half werk; goed gereedschap trouwens ook niet. Niets is ooit onmogelijk voor hen die het niet hoeven te doen.
trix

Golden Member

zo,..dat is allemaal nog niet zo simpel als ik het zo lees.
ik weet nog niet eens zeker of ik wel een stop bit heb ? toch maar eens goed induiken.

eigenwijs = ook wijs

Al het gedoe met extra bytes verzenden is niet nodig. Ook pullups etc niet. Een RS485 transmitter chip houdt zelf de lijn in een correcte idle state wel natuurrlijk op de correcte manier op je CPU aansluiten. Je hebt toch wel de lijn aan het begin en einde netjes met 120 Ohm afgesloten?

Sterker nog, die extra meuk verzenden is heel onhandig omdat je dat weer in je protocol moet wegwerken.

Op 10 april 2020 19:23:27 schreef trix:
mischien moet ik inderdaad checken of de buffers wel leeg zijn, voordat ik ze omschakel naar de zend/ontvangst mode.

Vrijwel zeker zit daar je probleem.

Wat ook nodig is, is inderdaad zorgen dat je tussen het omschakelen naar transmit of receive mode een kleine tijd wacht, dat is de tijd dat de instructie je I/O poort aanstuurt en de "turnaround tijd" van RS485 transceiver. Net even een maxim driver opgezocht (MAX485) en daar is de tijd maximaal 3 us tussen de DE pin sturen en dat deze uit gaat. Aanzetten is sneller: 2 us.
Dat kan tricky worden als je volledig interrupt driven de boel werkend probeert te maken. Ook je cpu instructie naar pin output word intern geclocked en naar de output, vergeet die delay ook niet mee te tellen.

Dat is wat fatbeard bedoeld en zegt dat je een bittijd wacht voordat je begint te zenden. De RS485 driver krijgt dan de kans om om te schakelen.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.

In ASM een byte via RS485 versturen (tx):

avr asm code:

nextTX:	ldi	temp, 0b10101010			;set test data
waitUDR:sbis	UCSRA, UDRE			;wait UDR ready
	rjmp	waitUDR
	out	UDR, temp			;transmit test data
waitTX:	sbis	UCSRA, TXC			;wait for TX ready
	rjmp	waitTX
RES
fatbeard

Honourable Member

Op 10 april 2020 21:35:43 schreef henri62:
... Een RS485 transmitter chip houdt zelf de lijn in een correcte idle state wel natuurrlijk op de correcte manier op je CPU aansluiten.
...

... en hoe is die 'correcte idle state' dan precies gedefiniëerd? >:)

'Idle' betekent 'floating', oftewel hoogimpedant; daar is niets gedefiniëerd aan. Sommige setups doen er te iets lang over om van floating naar active te gaan, en verliezen daarmee het startbit (al gaat dat in de meeste gevallen wel goed). Let wel: niet elke UART doet dit (goed), beter is het om dat zelf te regelen.
Het biasen van de lijn met een paar weerstanden heeft, zoals gezegd, ook een tweede functie: je kunt vaststellen of de verbinding fysiek nog intact is.
Afsluiten van de lijn met een min-of-meer correcte impedantie is aan te raden, maar bij relatief korte afstanden en lage baudrates niet meteen noodzakelijk. Zo is bij 2400 baud een niet getermineerde lijn van 10 meter geen probleem, bij 115k2 wel.

Stopbits worden door de meeste UARTs 'vanzelf' toegevoegd, dat is een van de instellingen (keuze uit 1, 1½ of 2); de ontvanger dient te worden ingesteld op een aantal dat in elk geval niet groter is. Het stopbit geeft extra marge in de synchronisatie tussen zender en ontvanger, voor het geval dat de baudrates niet helemaal kloppen door bijvoorbeeld temperatuurverschillen.

Een veelgemaakte fout is het afzetten van de transmitter vóórdat het laatste bit (dat stopbit dus) ook daadwerkelijk is verzonden: niet alleen de buffer maar ook het transmit register moet echt leeg zijn. Omdat dat stopbit niet in het transmit register staat wordt het vaak over hoofd gezien.

Een goed begin is geen excuus voor half werk; goed gereedschap trouwens ook niet. Niets is ooit onmogelijk voor hen die het niet hoeven te doen.
trix

Golden Member

Op 10 april 2020 21:35:43 schreef henri62:
Je hebt toch wel de lijn aan het begin en einde netjes met 120 Ohm afgesloten?

jazeker, ik kan immers wel master -> slave opdrachten versturen.

eigenwijs = ook wijs
trix

Golden Member

wat getest, werkt nog niet, maar alvast een stukje verder met het lokaliseren v/h probleem.

1 - ik stuur van master -> slave opdracht: send your data to me
2 - in slave: opdracht komt keurig aan en slave zet zijn data op de bus,
dit gecontroleerd met LA, en ik zie het bit patroon terug, 10101010.

als je wat betreft stopbits in de registers niks selecteert heb je 1 stopbit
die zie ik niet, wel iets wat op 2x een startbit lijkt.

het gaat dus waarschijnlijk fout in het ontvangen v/d byte door de master.
ik post een print screen v/d LA, en een stukje code v/d master.
dus onder: //*** below: receiving the data from the TSOP gaat het fout. hij komt al niet voorbij die 1e IF (gecheckt met LED)
wie ziet wat er fout gaat ?.......bedankt.

MASTER:

c code:


if (button_increase)  // for testing send to TSOP: send your data to me
{
					
//*** below: sending from request to TSOP: send me your data **********************************************					
PORTE |= (1 << PINE2); // switch MAX485 as transmitter pin 2 & 3 = "1"
PORTE |= (1 << PINE3); // switch MAX485 as transmitter pin 2 & 3 = "1"

UCSR0B &=~(1 << TXB80); // Make the TXB8 bit 0 for the moment
					
_delay_ms(1);
if (adress == 1)
{
UCSR0B |= (1 << TXB80); //Set the TXB8 bit (9e bit) to 1: we gonna send a addres
}

_delay_ms(1);
while ((UCSR0A & (1 << UDRE0)) == 0) {}; // do nothing till the UDR is ready to receive
bytetosend = 0b00000010; // is the adress TSOP
UDR0 = bytetosend;
					
_delay_ms(1);
while ((UCSR0A & (1 << UDRE0)) == 0) {}; // do nothing till the UDR is ready to receive
bytetosend = 0b00000011; // is the data: TSOP send your data to me.
UDR0 = bytetosend;
					
_delay_ms(1);
while ((UCSR0A & (1 << UDRE0)) == 0) {}; // do nothing till the UDR is ready to receive
bytetosend = 0b11111111; // is the data witch is the stop code
UDR0 = bytetosend;					
				
				
//*** below: receiving the data from the TSOP *********************************************************

if (UCSR0A & (1 << TXC0) == 1) // if the the data in the transmit shift reg. is shift out
{						
PORTE &= ~(1 << PINE2); // switch MAX485 as receiver pin 2 & 3 = "0"
PORTE &= ~(1 << PINE3); // switch MAX485 as receiver pin 2 & 3 = "0"
					
_delay_ms(10);
					
while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
receivedbyte = UDR0; // Fetch the received byte value into the variable "ReceivedByte"
					
_delay_ms(10);
					
if (receivedbyte == 0b10101010)
{
PORTB |= (1 << PINB7); // LED = 1 just for checking GEEL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
					
_delay_ms(10);
					
PORTE |= (1 << PINE2); // switch MAX485 as transmitter pin 2 & 3 = "1"
PORTE |= (1 << PINE3); // switch MAX485 as transmitter pin 2 & 3 = "1"
}
eigenwijs = ook wijs
Arco

Special Member

I2C (eventueel met P82B715's) lijkt me veel simpeler. Geen gehannes met omschakelen master/slave...

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

Golden Member

eigenwijs = ook wijs
fatbeard

Honourable Member

dit gecontroleerd met LA, en ik zie het bit patroon terug, 10101010.

als je wat betreft stopbits in de registers niks selecteert heb je 1 stopbit
die zie ik niet, wel iets wat op 2x een startbit lijkt.

Ik zie één startbit, gevolgd door 01010101 en één stopbit.
Bitjes worden 'LSB first' verzonden, in het begin tamelijk verwarrend...

Voor RS485 is het bekijken van de datalijn(en) veel interessanter: dan kun je ook zien of de lijn wordt vrijgegeven, en of er misschien twee zenders tegen elkaar in staan te praten. Voor dat laatste neem je twee weerstandjes van 10Ω in serie met elke lijn op.

Ik heb al veel communicatieprobleen op die manier weten te identificeren en op te lossen.

Een goed begin is geen excuus voor half werk; goed gereedschap trouwens ook niet. Niets is ooit onmogelijk voor hen die het niet hoeven te doen.
Arco

Special Member

Op 11 april 2020 14:38:01 schreef trix:
(veel) te traag.

Je pakt het ook verkeerd aan. Continu pollen is zinloos en tijdverspilling.
Laat de receiver alleen zelf data versturen als de toestand verandert. Dat spaart je 99.999% communicatie uit... ;)

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

Golden Member

Op 11 april 2020 19:03:26 schreef Arco:
[...]
Laat de receiver alleen zelf data versturen als de toestand verandert. Dat spaart je 99.999% communicatie uit... ;)

de receiver verstuurt toch geen data ?

Op 11 april 2020 18:50:47 schreef fatbeard:
[...]
Ik zie één startbit, gevolgd door 01010101 en één stopbit.
Bitjes worden 'LSB first' verzonden, in het begin tamelijk verwarrend...

verdorie, inderdaad, het is maar net hoe je het bekijkt.

[Bericht gewijzigd door trix op zaterdag 11 april 2020 19:44:48 (31%)

eigenwijs = ook wijs

Data klopt niet helemaal.

Inderdaad een start bit gevolgd door data 01010101 (zoals verwacht, achterstevoren op de lijn), maar dan volgt er nog een nul bit. Zal wel een parity zijn. Daarna word de lijn weer hoog, dat is dan het stop bit, gevolgd door een periode idle.

Arco

Special Member

de receiver verstuurt toch geen data ?

Nee,

Daar zit ook het probleem/fout... ;)
Wat heeft het voor zin om aan al die receivers continu te vragen of ze wat gezien hebben???
Daarbij is het nog inaccuraat ook: je krijgt de info pas als het event al lang voorbij is.

(bij andersom werken is de info real-time)

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

Golden Member

voor de duidelijkheid, met receivers bedoel je toch de slave's ?

ik vraag toch niet continu aan de receivers/slaves om data te sturen, daar vraag ik alleen om als ik op de enter knop druk.

eigenwijs = ook wijs
Arco

Special Member

Ja,

Maar 't is toch vele malen efficienter als je die slave zelf laat melden dat er wat aan de hand is?
Nu moet je alle 300 slaves uitlezen, en (waarschijnlijk) hun toestand vergelijken met de toestand bij de vorige scan?

Als de slave zelf meldt dat de status is gewijzigd, dan weet je zonder verdere test welke slave dat is en wat de toestand is...

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

Als dit nog steeds dat project is om een "scan" van een object te maken met 300 IR zenders aan 1 kant en 300 ontvangers aan de andere dan weet de master dat zender 123 aan is en is alleen ontvanger 123 van belang.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

RS485 MOET je terminaten, niks korte stukjes werkt wel. Is gewoon niet zo en totaal onbetrouwbaar.

In tegenstelling wat gezegd wordt dat het 2-draads verbinding is heb je bij RS485 ook je GND nodig. Ik naam aan dat je de master en slave kwa GND aan elkaar hebt hangen?

@fatbeard: Met de idle state bedoel ik de verbinding tussen de CPU en de transceiver (dus NIET de twisted pair lijn). Dat zijn over het algemeen totempole uitgangen.

@Arco: Ook de ontvanger zelf iets laten zenden is eigenlijk slecht aan de praat te krijgen, je moet dan zelf een CSMA protocol gaan implenteren met checksums of CRCs anders is het helemaal hopeloos. Kortom niet aan beginnen als je dit al niet werkens krijgt, of de boel wegmikken en CAN gebruiken waar dit netjes opgelost is in het protocol.

In RS485 land wordt of een master-zend/ slave-response gebruikt OF een token ring achtig protocol, waarbij er bijna altijd speciale IC's worden gebruikt die het hele protocol afhandelen.

Ik zie hier ook 9 bits op de lijn, gebruik je (bewust) parity? Anders is er nog meer aan de hand. 9-bits transmissie gebruikt vrijwel niemand.

1-st law of Henri: De wet van behoud van ellende. 2-nd law of Henri: Ellende komt nooit alleen.
trix

Golden Member

edit: post henri62 heeft gekruisd.

het zijn geen 300 slaves, het zijn er voor als nog 2 (worden er later 12)

1 slave is: een atmega16 waarop 24x receiver is aangesloten = 3 byte.
op een bepaald moment is die atmega16 gevuld met 900 bytes aan data.
pas dan word er gevraagd aan de slave: "send me your data"
dan moet ik dus in 1x keer die 900 byte aan data naar de master sturen.

ja, ik heb afsluit weerstanden en de GND hangen aan elkaar, ik kan immers al wel data master --> slave sturen. dus de hardware lijkt mij dan in orde.

nee geen parity.....het zijn toch 10 bits ?

eigenwijs = ook wijs