hallo, ik heb een simpele start opstelling gemaakt om het SPI gebeuren te testen, 1 master en 1 slave.
het gaat om de data v/d slave naar de master, in de slave staat deze in een array.
het probleem is, dat wanneer de SPI de 1e byte naar buiten shift, er eerst een aantal bytes komen met 0x00 (maar ik verwacht als 1e byte 0x255 (1e byte in de array)). dat aantal bytes met 0x00 is random. zodra de 1e byte uit de array verschijnt komt de hele array er correct achter aan.
in de datasheet staat, zodra de SS laag word start de SPI de pulstrein en shift zijn SPDR naar buiten, dan zou dus meteen de SPDR in de slave ook over de MISO naar de master moeten gaan.
als test heb ik nog in de slave SPDR = 0x255 dus zonder de hele array, en dat gaat wel goed. het lijkt hem dus echt in het array gebeuren te zitten.
ik test het een en ander met een logic analyzer, de blauwe lijn onder aan is de SS. (SS_TSOP).
ik hoop dat iemand hier ziet wat er nou fout gaat, alvast bedankt.
MASTER
//*******************************17-8-2019 TEST PSI****************************
//**********************************MASTER**************************************
#define F_CPU 1000000UL // 1 MHz int osc
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
int main(void)
{
char data;
DDRB |= (1<<PINB1)|(1<<PINB2)|(1<<PINB0); // SCK, MOSI and SS as outputs
DDRB &= ~(1<<PINB3); // MISO as input
DDRC = 0b11111111;
SPCR |= (1<<MSTR); // Set as Master
SPCR |= (1<<SPR0)|(1<<SPR1); // divided clock by 128
SPCR |= (1<<SPE); // Enable SPI
while(1)
{
_delay_ms(1);
PORTC &= ~(1 << PINC5); // maakt SS laag
SPDR = 0b01010101; // send the data
while(!(SPSR & (1<<SPIF))); // wait until transmission is complete
PORTC |= (1 << PINC5); // maakt SS hoog
}
}
SLAVE
//****************17-8-2019 TEST PSI*****************************************************
#define F_CPU 1000000UL // 1 MHz int osc
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
int testers [38] = {255, 0, 255, 0, 255, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,} ;
int bytenr;
int data;
//*****************************SLAVE*********************************************
int main(void)
{
// char data;
DDRB &= ~((1<<PINB7)|(1<<PINB5)|(1<<PINB4)); // SCK, MOSI and SS as inputs
DDRB |= (1<<PINB6); // MISO as output
SPCR &= ~(1<<MSTR); // Set as slave
SPCR |= (1<<SPR0)|(1<<SPR1); // divide clock by 128
SPCR |= (1<<SPE); // Enable SPI
while(1)
{
for (bytenr=0; bytenr<38; bytenr++)
{
while(!(SPSR & (1<<SPIF))); // wait until all data is received
SPDR = testers[bytenr]; // hurray, we now have our data
}
}
}
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
De status van de SS lijn heeft niets met het versturen van de data te maken...
(je kunt rustig de SS lijn laagtrekken en pas na een uurtje de data ophalen...)
SS laag is alleen een teken dat de betreffende slave actief is op de SPI bus.
Verder stuurt de slave niets spontaan, maar in antwoord op een vraag van de master.
(voor commando's en hun opbouw zie datasheet van de slave)
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Normaal gesproken moet je wel iets zinvols sturen. (een commando wat de slave begrijpt en zo weet wat 'ie moet doen...)
Klokpulsen komen alleen als je een commando of byte via MOSI verstuurt. Dat kan direct, maar ook een uur later. (als extreem voorbeeld... )
ja klopt, dat had ik hierboven al toegevoegd.
die dummy byte mag toch van alles zijn, maakt niet uit wat. de slave doet er toch niets mee.
maar in mijn geval stuur ik de dummy meteen na dat de SS laag word.
[Bericht gewijzigd door trix op (20%)]
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Je moet de byte gewoon 'klaarzetten in het SPI TX register op de slave. Dan wordt die verzonden als er wat binnenkomt.
Ik weet niet hoe de SPI bij die Atmega werkt, maar meeste Pics hebben een 8 byte fifo buffer, zodat je al 8 bytes klaar kunt zetten...
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Als je een "startopstelling voor het SPI gebeuren" wilt maken, waarom dan niet een echt SPI device nemen en alleen de master zelf programmeren? Dan heb je maar 1 onzekere kant waar je aan kunt sleutelen. De andere kant, de slave, is dan een vast gegeven met documentatie in de datasheet.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Zelf een slave maken is best te doen, alleen is het een hoop uitzoeken en proberen. (omdat maar weinigen het gebruiken is er weinig over te vinden)
Ik gebruik pics vaak als i2c slave. (die dan een bestaand i2c ic emuleren)
for (bytenr=0; bytenr<38; bytenr++)
{ while(!(SPSR & (1<<SPIF)));
SPDR = testers[bytenr];
}
Verkeerde volgorde. SPIF wordt hoog nadat het eerste byte al verstuurd is. En dan is er nog geen data in SPDR.
Zo zal het wel beter gaan:
for (bytenr=0; bytenr<38; bytenr++)
{ SPDR = testers[bytenr];
while(!(SPSR & (1<<SPIF)));
}
Maar een goede master moet er rekening mee houden dat zijn slave nog niet wakker is. Dus die moet blijven proberen totdat de juiste data terugkomt.
Die timing verklaart overigens maar een enkele 0x00 byte terwijl de trace meerdere 0x00 bytes laat zien. Blijkbaar gaat de master al transmitten terwijl de slave nog niet is opgestart?
Het is meestal geen goed idee om in main al meteen in de eerste microseconde aktief te worden. Misschien heeft de slave een andere voeding, die trager opstart, of een grotere reset condensator, of een groter opstart delay, of ... enz.
Het kan dus helpen om in de master een delay van bijv 500 milliseconden af te wachten voor de loop te starten.
[Bericht gewijzigd door deKees op (50%)]
nee ze zitten beide op dezelfde labvoeding.
Op 21 augustus 2019 22:13:31 schreef Arco:
Zelf een slave maken is best te doen, alleen is het een hoop uitzoeken en proberen. (omdat maar weinigen het gebruiken is er weinig over te vinden)
Ik gebruik pics vaak als i2c slave. (die dan een bestaand i2c ic emuleren)
ik dacht dat dat veel meer werd gedaan.
het gekke is dat wanneer ik in de SPDR v/d slave direkt een waarde zet b.v. 0x255, dat het dan wel goed gaat. je ziet meteen bij de eerste klokpulsen de byte op de MISO lijn.
ik zal daar morgen eens een plaatje van posten.
Jouw master stuurt SS laag voor elke byte die verstuurd wordt, en weer hoog als de byte verzonden is. Dus feitelijk heb je 1-byte sessies.
In de slave gaat het nu mis. De SPI wordt aktief als SS laag wordt, maar dan is er nog geen data in SPDR. Vervolgens stuurt de master zijn data byte, en krijgt een leeg byte terug, want SPDR in de slave was immers nog niet geschreven. De slave schrijft pas in SPDR nadat de transmissie al gedaan is, die staat dus klaar voor de volgende transmissie, maar de master maakt SS dan weer hoog zodat de SPI in de slave wordt gereset.
Normaal wordt de data verstuurd in berichten van meerdere bytes. Dus dan gaat dat zo:
- Master maakt SS laag.
- Master verstuurt het eerste byte en krijgt 0x00 terug van de slave.
- Slave ontvangt eerste byte en schrijft antwoord in SPDR.
- Master moet de slave voldoende tijd geven en vervolgens de tweede byte versturen.
- Enz. SS blijft laag totdat de hele sequence is afgehandled. Pas dan wordt SS weer hoog.
Als de response op het eerste byte al meteen goed moet zijn, dan moet de slave al in SPDR schrijven voordat het eerste bit van het eerste byte al verzonden is. Dus zekere niet wachten op SPIF want die wordt pas hoog nadat er een heel byte binnen is gekomen.
even voor de duidelijkheid, deze slave die ik wil maken is enkel en alleen bedoeld om het programma in de master te kunnen testen. straks komen de bytes die nu uit de slave komen van een ander device.
nog wat testjes gedaan, maar ik krijg de synchronisatie niet goed, dus ik dacht dan maar wat symptoom bestreiding, als ik maar kan testen. dus ik gooi die eerste "0 bytes" weg (hoeveel het er ook mogen zijn) en ga dan verder. alleen nu krijg ik zo nu en dan wat losse bits op de MISO lijn waardoor het ook niet gaat werken.
ik krijg het idee dat ik verder en verder weg dwaal van het geen ik wil, en dat SPI toch niet de juiste bus/protocol is voor het geen wat ik straks moet gaan doen.
dat word nog versterkt door de reacties hier dat het niet erg gebruikelijk is om zelf een slave te maken (waarom zou ik dat dan wel doen ?).
dus terug naar de basis: wat ik moet doen:
- ik heb straks een device waarin 19x een atmega 8 zit
- in elke atmega 8 zitten 600 bytes
- die moeten op een bepaalde volgorde naar de hoofdprint (atmega 128)
- kabellengte device -> hoofdprint = 10mtr.
dat is het eigenlijk, in de hoofdprint worden die bytes opgeslagen in externe RAM (23LC1024) dat werkt al.
wat is de best aangewezen oplossing ? waarvoor mijn dank uiteraard, jullie bijdragen worden enorm gewaardeerd.
benleentje
Golden Member
Als je 19 + master is 20 units hebt is het verstandig om alles geadresseerd te gaan aansturen. Je zou dat via i2C kunnen doen dat werkt met adressering en hoef je niet voor elke slave een aparte SS lijn te hebben.
IK denk wel dat SPI kan werken maar dan wel zoals de kees het beschrijft en anders ook even algemene SPI protocol in PDF eens doorlezen. Je schrijft dan wel zelfs de software voor slave en dat deel is dus wel vrij maar de onderliggende hardware werkt dan toch zoals het normale SPI protocol en dan moet je ook in de goede volgorde werken en je slave de tijd geven om te kunnen antwoorden.
Op 23 augustus 2019 13:49:46 schreef Arco:
[...]
Dat lokt natuurlijk de vraag uit: waarom...(kan dat niet met 1 processor?)
ik heb 300 input pinnen nodig.
ik ga eens de i2c bekijken, ik heb dat in het verleden al vaker gebruikt (o.a. I/O extension), maar naar mijn weten is dat bedoeld voor korte afstanden.
met dat SPI ben ik wat deze toepassing betreft wel klaar, ik gebruik het nog wel om de externe RAM (23LC1024) aan te sturen.
maar ik was van plan om alle atmega's als een soort 74HC595 te programeren en dan bij de laatste atmega de verzending met SPI naar de atmega128 te maken.
edit:
uart is ook nog steeds een optie, moet dat beter bekijken.
[Bericht gewijzigd door trix op (11%)]
Op 22 augustus 2019 18:31:57 schreef Arco:
Voor communicatie tussen CPU's is de UART veel simpeler in gebruik...
Bij AVR's kan je een USART in SPI mode zetten, het is dus bijna hetzelfde.
Zie pagina 202.
http://www.microchip.com/mymicrochip/filehandler.aspx?ddocname=en59046…
Volgens mij is het voordeel van SPI dat het bloedsnel is. Elk bit krijgt een clockpuls mee. Goed voorbeeld is te vinden bij aansturing meerdere stappenmotordrivers zoals bij de Arduino-controlled 3D printers.
Een UART moet (intern) gewoonlijk 16 MCU clockpulsen per bit hebben.
En I2C is nog slimmer maar ook weer langzamer. Hoofdvoordeel is voor mij dat je met maar 2 communicatie draadjes heel veel IC's aan elkaar kan knopen.
[Bericht gewijzigd door Spog2 op (40%)]
Op 23 augustus 2019 17:48:59 schreef trix:
het hoeft helemaal niet snel te zijn, er moeten in totaal 11400 byte van de device naar de hoofdprint, en daar mag hij ong. 2 sec. over doen.
Normaal gesproken zou je dan i2c nemen.
Maar ik heb ooit wel eens wat onderzoek gedaan wat er bij komt kijken als je zelf een i2c protocol zou willen implementeren. Leek me bij nader nog niet zo eenvoudig, en ben er toen niet op doorgegaan.
Een een chip of display met i2c uitlezen is nog even iets anders dan een chip met i2c uitleesbaar te maken. Er zijn mechanismen voor fouten, multimaster en zo. Dat meerdere divices tegelijk aangesproken worden of juist bezig zijn moet je in goede banen zien te sturen.
Maar als je het simpel kan houden en het hoeft niet supersnel dan zou ik voor i2c gaan.
[Bericht gewijzigd door Spog2 op (13%)]
benleentje
Golden Member
Er zijn mechanismen voor fouten, multimaster en zo. Dat meerdere divices tegelijk aangesproken worden of juist bezig zijn moet je in goede banen zien te sturen.
Dat is bij TS niet van belang er is maar 1 master.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Met 9600 baud ga je geen 11400 bytes in 2 sec. halen...
RS-232 kan prima, maar dan moet 't wel wat rapper... (je haalt aan bytes ongeveer de baudrate/10 )
ik had verwacht dat het versturen van 11400 bytes over 10 mtr. eigenlijk geen probleem zou zijn. toch iets lastiger dan gedacht.
ik moet gewoon de juiste methode zien te vinden. die 2 sec. is ook niet strikt, 4 sec. is ook geen probleem.
maar bestaan er rs485 modules (of ander bus/protocol) zoals ik voorstelde op met mijn 5 posts terug ?
ik kan nog de P82B715 extender voor i2c bekijken zoals arco voorstelde.
maar een i2c slave maken is schijnbaar ook niet eenvoudig.
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Ik heb het topic niet helemaal meer gevolgd, maar pik toch wat dingen op. Volgens mij is het hardware design heel erg uit de bocht aan het vliegen. Je doel is (denk ik) heel veel I/O aan sturen, en dat probeer je te bereiken met 20 microcontrollers die als SPI-slave staan en die door een andere micro wordt aangestuurd. Omdat je SPI gebruikt neem ik aan dat het ook nog eens allemaal op 1 board zit. Het is niet vervelend bedoeld hoor, maar dat voelt voor mij als een heel erg lelijke oplossing.
Wat ik zou doen: 1 enkele micro die de aansturing doet. Met I/O expanders op I2C sluit je zoveel I/O aan als je maar nodig hebt. Ik weet dat er ICs zijn met (uit m'n hoofd) 40 pinnen per IC, dus dat loopt lekker op. I2C zijn voor veel micros standaard library functies, dus dan wordt het ineens appeltje-eitje.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Converteren is allemaal lap-werk. Maak het nou gewoon goed. Eigenlijk hoort dat denkwerk al in je ontwerp-fase. Nu ben je al veel te ver op weg om die aanpassing pijnloos te doen. Nu kost je het heel veel werk. Maar je moet als je het werkend wilt krijgen.
Als je rs485 wilt gebruiken: op zich is dat gewoon een asynchrone seriele interface, net zoals een uart verbinding. RX en TX lijntje. Het protocol kun je zelf bedenken, bv:
start-patroon, address, msg-lengte, data
...maar dat bepaal je volledig zelf als je zelf de software aan beide kanten van de lijn schrijft.
conventeren is inderdaad lapwerk. mijn kennis in bus systemen rijkt natuurlijk niet ver. dan is het kiezen van de juiste bus/protocol heel moeilijk, maar die keuze is wel heel belangrijk, want die verander je niet zo maar even.
de verandering is niet zo pijnlijk, ik heb i.p.v. 19 PCB,s er nog maar 4 gemaakt om wat te kunnen testen.
ik zal straks eens een tekeningetje posten v/d situatie, maakt het wat overzichtelijker voor iedereen.