logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[AVR] Pominięcie przerwania TXC raz na kilka tys. wysłanych

hotdog 29 Paź 2010 10:29 2797 22
  • #1 8677049
    hotdog
    Poziom 26  
    Witam. Robiłem znajomemu "składaka" na szybko z posiadanych kodów. Urządzenie ma wykonywać pomiar z 8 czujników podłączonych do oddzielnych pinów uC (PC0-PC7). Samo urządzenie działa ok. Odczyt temp, transmisja via rs485.

    Niby było wszystko ok, ale czasami potrafiło się zawiesić. Dlatego włączyłem WDT. Niby częstość zawieszeń spadła. Ale niestety urządzenie dalej się zawiesza. Całość już mi zajmuje 3x więcej czasu niż chciałem żeby zajęła. Urządzenie zawiesza się tylko przy rzeczywistym odczycie z czujników. Jeżeli sobie np na sztywno wpiszę dane do wysłania (nie uruchamiam funkcji 1Wire) wszystko działa godzinami.

    Co może powodować takie zawieszenie się urządzenia, że WDT też się zawiesza?

    BOD mam włączony, taktowanie z kwarcu 16MHz.

    Urządzenie jest trochę polutowane na płytce do tego nie do końca przeznaczonej, ale tutaj chyba problem nie leży.

    Pozdrawiam

    Dodano po 2 [minuty]:

    W sumie chce już pomału dołożyć oddzielny reset wykonany z attiny13. Główny uC będzie puszczał kwadrat na jakimś porcie. Jak tiny nie wykryje zmiany przez kilka us, to ściągnie reset w dół.

    Pozdrawiam
  • #2 8677064
    tmf
    VIP Zasłużony dla elektroda
    WDT się nie wiesza, po prostu dajesz WDR tam gdzie tkwi problem :) No i sam sobie odpowiedziałeś - kaprawo napisane 1W. Obstawiam, że w jakiejś pętli masz nieskończone oczekiwanie, bo nie testujesz warunków błędów na magistrali 1W, np. zwarcie na stałe. Poza tym WD nie rozwiązuje ci problemu - po prostu zamiast wieszania się układ się resetuje, ale ciągle działa kaprawo. Zmieniłeś tylko tyfus na dżumę :)
  • #3 8677176
    hotdog
    Poziom 26  
    To czy WDT eliminuje problem czy nie to już zależy od programu. Czasami warunki w jakich urządzenie pracuje może spowodować np zmianę licznika PC i wtedy program siedzi tam gdzie nie powinien. Są to sytuacje ekstremalne. Większość z nich eliminuje BOD, ale nie wszystkie.

    W sumie przeleciałem program na szybko i nie mam takich warunków które w moim mniemaniu mogły by program zawiesić. Samą transmisję mam przez IRQ i w sumie po zawieszeniu się uC nawet mi dioda nie mrugnie od RXTX. Przerwań nigdzie nie blokuje, ani nie wyłączam przerwania od UARTA. W samym 1Wire nie ma sensu dawać jakichś takich warunków. Ogólnie funkcje są na delay'ach. Dane są poprostu samplowane w środku okna czasu i tyle. Jak nie ma czujnika to funkcja odczytu bajtu zwraca 0xFF, a funkcje odczytu temperatury błąd CRC.

    A pętla główna wygląda tak:
    	while(1)
    	{
    		if (IsPacketRecived())
    		{
    			ProtocolParsePacket();
    		}
    		wdt_reset();
    	}

    Obsługa przerwania USART RX:
    SIGNAL (USART_RXC_vect)
    {
    	LED_RXTX_BLINK();
    	uint8_t recived = UART_getchar();
    	if (isPacketRecived)
    		return;
    	switch(reciverStatus)
    	{
    	case WaitingForPreamble:
    		if (recived == PREAMBLE)
    		{
    			bytesRecived = 0;
    			bytesToRecive = 0;
    			currentCRC = 0x00;
    			reciverStatus = RecivingHeader;
    		}
    		break;
    	case RecivingHeader:

    Oczywiście mogłem gdzieś popełnić błąd przez co funkcja IsPacketRecived() w pewnych warunkach będzie zawsze fałszywa, ale i tak dioda powinna mi mrygnąć przy odebraniu znaku. Makro LED_RXTX_BLINK() powoduje zapalnie diody. Timer ją gasi po jakimś tam czasie. Dioda po zwieszeniu się nawet się nie zapali jak dane lecą via uart do uC.

    Pozdrawiam

    Dodano po 3 [minuty]:

    No i zauważyłem że urządzenie tak jak by za oknem zawiesza się bardziej (w niskiej temperaturze) niż w domu (oczywiście urządzenie zabezpieczone woreczkiem przed wilgocią :)
  • #4 8677230
    tmf
    VIP Zasłużony dla elektroda
    No nie, jeśli program się wiesza to WD nigdy nie jest rozwiązaniem. WD to ostatnia deska ratunku, w sytuacjach nieprzewidywalnych, jak np. atak marsjan. Jeśli zakłócenia są tak potężne, że wpływają na procesor to znaczy, że układ jest źle zaprojektowany/wykonany/użytkowany w warunkach, do których nie był przeznaczony.
    Z kodu, który pokazałeś niewiele wynika - może gdzieś masz problem z atomowością dostępu, ale to tylko strzelam. Co do WD - jesteś pewien, że go uruchomiłeś? Dla pewności zaprogramuj fusebit WDON. Jeśli program jest ok to spróbuj na innym procku, inna możliwość to taktowanie. Masz kwarc, czy jedziesz na wewnętrznym RC? Może któryś z zewnętrznych elementów, np. kondensator jest uszkodzony. Zdechnięcie zegara dawałoby takie objawy. A diagnostycznie - masz JTAG? Podłącz układ i zobacz na czym zdycha.
  • #5 8677303
    hotdog
    Poziom 26  
    Np teraz układ działa od godziny bez problemu, chociaż nie wiem ile razy już został przez WDT zresetowany (i czy w ogóle).

    Resety mu nie przeszkadzają, bo jest to zrobione w sposób master-slave czyli uC odpowiada na komendy przesłane z komputera. Ich częstość wynosi 1s (najpierw odczyt, później komenda konwersji i 1s przerwy). Funkcja ProtocolParsePacket() robi w sumie 2 rzeczy. Pierwsza to to Wykonuje jakieś akcje, czyli Convert i Read z czujników w zależności od tego jaki Pakiet został otrzymany. Jeżeli otrzymaliśmy pakiet odczytu, to uC przygotowuje buffor do wysłania i wysyła jeden bajt do rejestru UDR (reszta jest robiona w przerwaniu).

    Ja sam dochodzę do wniosku, że "zamieszanie" na portach od 1Wire zawiesza procesor. Ale nie mogę znaleźć sensownego powodu czemu by tak miało być. Wiem że urządzenie nie jest zrobione idealnie, bo jest zbudowane na płytce która nie była do tego przeznaczona. W sumie w uproszczeniu można powiedzieć że jest zbudowane na płytce uniwersalnej. Ale przy takich (czujniki 1Wire) zastosowaniach wydaje się to mniej istotne.

    Niestety nie włączę WDT w fusach bo atmega16 nie ma takiej opcji :(

    Samego Jtaga mam, ale urządzenie nie ma wyprowadzonego portu, bym musiał na kabelkach się wlutować. Tylko że akurat jeden z pinów mam jako RS485_RW zrobiony (sterowanie kierunkiem transmisji) i musiał bym go przełączyć na inny.

    Z kodu miało wynikać, że jeżeli procesor się nie zawiesił, to dioda by zamrugała po odebraniu znaku.

    Sam kod protokołu pracuje godzinami bez problemu dopiero po dodaniu czujników się kaszani.

    Pozdrawiam
  • #6 8677369
    tmf
    VIP Zasłużony dla elektroda
    To sprawdzaj flagę WDRF w rejestrze MCUCSR - będziesz wiedział czy WD zresetował procka. Info o tym możesz wysłać na PC. W procedurach 1W sprawdź czy w jakimś miejscu nie masz nieskończonego czekania na jakiś określony stan linii. Oczywiście to by zwieszało procka tylko w sytuacji, w której jednocześnie nie włączałbyś WD - swoją drogą pokaż jak go włączasz.
  • #7 8678273
    hotdog
    Poziom 26  
    W sumie doszedłem do tego że procesor w sumie nie wisi, tylko MAX485 się przestawia na nadawanie i tak zostaje.

    Kod w którym tylko zmieniam kierunek transmisji. Jest to tak że cały czas jest odbiór, a jak otrzymam jakiś pakiet, i na niego chce odpowiedzieć, najpierw go przygotowuje w buforze, później wysyłam (w tym momencie przestawiam na nadawanie. W przerwaniu wysyłam kolejne bajty, a po zakończeniu ostatniego (mniej niż 1 bajt do wysłania) ustawiam MAX'a na odbiór. Wiem że to nie cały kod ale to najistotniejszy fragment. Makra PF_XXXX to zmienne które określają miejsca w pakiecie poszczególnego pola. W sumie zdaje sobie sprawę że jest to trochę namotane, ale najdziwniejsze jest że kod działa komputer wyśle i odbierze 2k5 pakietów i się potrafi zablokować.

    
    /*
     * Function prepares packet to send. If there if system i currently sending
     * a packet it returns how much data is left to send. If function returns 0,
     * the packet is ready to be send via ProtocolSendPacket function.
     */
    uint8_t ProtocolPreparePacket(uint8_t prefix[],uint8_t cmd, void* data, uint8_t size)
    {
    	if (bytesToSend > 0)
    	{
    		LED_RXTX_BLINK();
    		return bytesToSend;
    	}
    	memcpy(uartBufferOut+PF_PREFIX,prefix, 2);
    	memcpy(uartBufferOut+PF_CMD, &cmd, 1);
    	memcpy(uartBufferOut+PF_ARGS, data, size);
    	uartBufferOut[PF_LENGTH] = size + 3;
    	return 0;
    }
    /*
     * Sends packet via UART. If packet is already sending it breaks and returns
     * number of bytes left to send. If success it returns 0.
     */
    uint8_t ProtocolSendPacket(uint16_t reciverAdress)
    {
    	if (bytesToSend > 0)
    	{
    		return bytesToSend;
    	}
    	RS485_SET_TRANSMIT();
    	memcpy(uartBufferOut + PF_DEST_ADDRESS,&reciverAdress,sizeof(uint16_t));
    	memcpy(uartBufferOut + PF_SOURCE_ADDRESS,&MyAddress,sizeof(uint16_t));
    	uartBufferOut[PF_CRC] = CountCRC(0x00,uartBufferOut,PF_CRC);
    	uartBufferOut[PF_DATA + uartBufferOut[PF_LENGTH]] = CountCRC(uartBufferOut[PF_CRC],uartBufferOut + PF_DATA,uartBufferOut[PF_LENGTH]);
    	bytesToSend = PF_DATA + 1 + uartBufferOut[PF_LENGTH];
    	ptrByteToSend = uartBufferOut;
    	LED_RXTX_BLINK();
    	UDR = PREAMBLE;
    	return 0;
    }
    /*
     * Interrupt run after transmission of byte via UART is finished.
     */
    SIGNAL(USART_TXC_vect)
    {
    	LED_RXTX_BLINK();
    	if (bytesToSend < 1)
    	{
    		RS485_SET_RECIVE();
    		return;
    	}
    	UDR = *ptrByteToSend++;
    	bytesToSend--;
    }
    


    Dodano po 1 [godziny] 23 [minuty]:

    w sumie doszedłem do tego że czasami zdarza się, że jak się soft wysypie, to zmienna bytesToSend jest większa od 0, czyli tak jakby nie wysyłało całego pakietu, ale czemu? Potrzebuje jakiegoś spojrzenia kogoś obcego na powyższy kod, bo ja tutaj błędu dostrzec nie mogę. Funkcje ProtocolSendPacket, oraz ProtocolPreparePacket nigdy nie są wywoływane w przerwaniach.

    Dodatkowo jestem poirytowany, bo mi debuger coś odmówił posłuszeństwa (wgrywa soft, ale debugować już nie chce). Ogólnie uważam że możliwości debugowania AVR'ów są mocno ograniczone. AVR studio jako edytor ma funkcjonalności nie wiele większą od notepada, za to w miarę dobre możliwości debugowania. Znowu debugowanie w eclipsie jest jakoś tak nie dopracowane.

    Pozdrawiam

    Dodano po 3 [godziny] 23 [minuty]:

    Już naprawdę tego nie ogarniam. Układ działał poprawnie przez ponad 2h. W tym czasie układ odebrał 8k2 pakietów. Błąd crc nie wystąpił ani razu. Układ się zawiesił 25s po wystawieniu za okno do temp ~6*C. W sumie jest blaszany parapet, może to ma tutaj znaczenie a nie temperatura?

    Z tego co widzę to poprawnie jest wysłanych 5 bajtów (1 we funkcji 4 w przerwaniu), a później crash. Zmienna bytesToSend zawiera wartość 38, a przerwanie już nie jest zgłaszane MAX wiesza się w trybie nadawania. Po ręcznym zresetowaniu zmianie wartości bytesToSend na 0 i przełączeniu w tryb odbierania komunikacja ożywa. Wiem że mogę sobie gdzieś tam w timerku sprawdzić, czy bytesToSend się zmniejsza, ale wolał bym znaleźć błąd niż to naprawiać w ten sposób.

    Pozdrawiam
  • #8 8684336
    hotdog
    Poziom 26  
    Dalej nie mogę załapać o co "mu chodzi".

    W skrócie wygląda na to że raz na ileś tam tysięcy razy przerwanie od Transmission Complete się nie wykona (dziwne jest że zawsze po 3 bajcie). Jest to dla mnie mega dziwne. Mam n pomysłów jak to naprawić na około (np ręcznie ustawić bit TXC w UCSRA jeżeli zmienna bytesToSend się nie zmienia (i >0) i nadajnik jest włączony). Ale IMO nie o to chodzi żeby to na około naprawiać.

    Wartości zmiennych w momencie zawieszenia:
    uintReciverStatus = 01
    uartBufferOut = 00 01 00 02 23 DF 61 72 72 00 80 AF 41 00 80 B5 41 00 00 AA 42 00 00 AA 42 00 80 BE 41 00 80 B7 41 00 80 B0 41 00 00 AC 41 DC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    uartBufferIn =  00 02 00 01 03 21 61 72 67 F0 00 B5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    bytesToSend = 27 
    bytesToRecive = 00 
    bytesRecived = 0A 
    isPacketRecived = 00 
    *ptrByteToSend = 02 
    RS485_IS_TRANSMITING() = 20 (czyli prawda) 


    Układ zawiesił mi się już 6 razy, po czym odczytałem wartości, a są one kropka w kropkę zawsze takie same. Procesor poprawnie wysyła 4 bajty (najpierw preambuła 0x55 później 3 w przerwaniu z bufora). Następnie wygląda na to że przerwanie TXC (Transmission Complete) się blokuje i nie wykonuje. Jak następnie ręcznie ustawię MAX'a na odbiór i zresetuje "bytesToSend" na zero transmisja rusza dalej. Oczywiście po odebraniu pakietu z żądaniem wysyłania danych.

    Będę zobowiązany za KAŻDĄ sugestię.

    Pozdrawiam
  • #9 8685657
    mirekk36
    Poziom 42  
    Ja ci coś podpowiem może się przyda. Akurat też teraz walczę z oprogramowaniem modułu Slave na RS485 ;)

    1. nie używaj SIGNAL tylko ISR (to tak na przyszłość) bo tak w ogóle to mieszasz na maxa SIGNAL(USART_TXC_vect) Jak się korzystało kiedyś z SIGNAL to się brało wektor któy też miał w nazwie SIGNAL_ a teraz używaj makra ISR i używaj tych wektorów bez SIGNAL w nazwie

    2. wysyłaj dane z bufora nie w przerwaniu USART_TXC_vect tylko w przerwaniu które jest zgłaszane gdy bufor jest pusty. Wtedy bez żadnego warnunku IF możesz spokojnie dawać przełączanie MAX485 na odbiór i odbędzie się to zawsze ładnie po zakończeniu wysyłania każdego znaku. Natomiast włączanie nadajnika MAX485 będziesz realizował właśnie w tym przerwnaniu od pustego bufora tuż przed załadowaniem znaku do UDR !!! i to wszystko.

    Będziesz miał wtedy zawsze jasną i klarowną sytuację, czyli przed każdym znakiem MAX485 przełączony zostanie na nadawanie natomiast bezpośrednio po wysłaniu zostanie przełączony na odbiór. Mi to działa pięknie na prędkości 115200
  • #10 8686004
    hotdog
    Poziom 26  
    Hej. Dzięki za rady. Najbardziej mnie wpienia, że to działa godzinami i raz kiedyś się zatnie.

    O ISR wiem, tylko to kod w sumie z przed blisko 2 lat, a wtedy byłem bardziej zielony. Sprawdziłem czy są jakieś różnice w kodzie wynikowym po zmianie i niestety nie ma. Ale i tak dzięki za monit.

    Ogólnie z logicznego punktu widzenia dużej różnicy między przerwaniami UDRE, a TXC nie ma. Nawet nie pamiętałem że jest jeszcze to przerwanie, rzeczywiście bardziej się nadaje do opróżniania bufora. Dzięki za przypomnienie o jego istnieniu.

    Jedyne co mi nie pasuje z tego co piszesz, to przestawienie z powrotem na nadajnik w przerwaniu od UDRE. To przerwanie mówi tylko że bufor jest pusty, w rejestrze przesuwny dane mogą być dalej nadawane. Wtedy przestawiając na odbiornik możesz uciąć jakieś bity (prawdopodobieństwo rośnie przy niskich prędkościach uarta i szybkim kwarcu). Przynajmniej tak mi się wydaje, czy coś nie tak rozumiem?

    Nie bardzo w sumie bym chciał robić to też robić tak jak proponujesz (czyli zmieniać zawsze stan na nadawanie i wracać do odbierania po każdym znaku). Na początek spróbuję wykorzystać UDRE do wysłania całego bufora. Jak bufor będzie pusty to:
    - wyłączę przerwanie UDRE
    - włączę przerwanie TXC

    w TXC wyłączę nadajnik i wyłączę przerwanie od TXC.

    Zobaczymy jak to się spisze. Jak będą dalej błędy to dokładnie wg Twojej koncepcji.

    Dzięki za odpowiedz.
    Pozdrawiam
  • #11 8686078
    mirekk36
    Poziom 42  
    ale coś zakombinowałeś za mocno z teorią, że:

    Cytat:
    Wtedy przestawiając na odbiornik możesz uciąć jakieś bity (prawdopodobieństwo rośnie przy niskich prędkościach uarta i szybkim kwarcu


    Toż w przerwaniu UDRIE włączasz nadajnik tylko i wyłącznie wtedy gdy coś jeszcze jest do nadania a jeśli nie to po prostu wyłączasz przerwanie UDRIE i bez sensu jest w tym miejscu włączanie przerwania TXC.

    TXC może być cały czas włączone - zauważ, że ono zostanie wywołane tylko wtedy gdy z bufora wyleci ostatni bit ramki, wtedy ładnie za każdym razem nadajnik zostanie wyłączony.

    Jak więc mogę wg ciebie przestawiając na odbiornik w TXC uciąć jakieś bity przy niskiej prędkości i szybkim kwarcu ??? Przecież pierwszym razem aktywujesz przerwanie UDRIE gdy coś wrzucasz do bufora, potem ono samo za każdym razem się wywołuje gdy bufor jest pusty nawet przy prędkości 120bps - pomyśl i przy kwarcu 20MHz - co to za różnica? Zatem gdy już mamy pewność że bufor pusty (bo wszystko wcześniej wylazło ;) i MAX 485 został przełączony na odbiór w TXC to teraz znowu przed wrzuceniem kolejnego znaku z bufora do UDR załączasz nadajnik. I znowu sobie on spokojnie wychodzi nawet w ślimczaym tempie 120bps. Ty nie musisz się w programie głównym martwić o wyłączenie nadajnika bo jak "slimak" zakończy wysyłanie ramki to po ostatnim bicie pojawi się przerwanie TXC i samo "posprząta" czyli wyłączy nadajnik.
  • #12 8686080
    hotdog
    Poziom 26  
    Zmieniłem kod, tak jak to opisałem i na razie działa od minuty. Zobaczymy co będzie przez godzinę.

    Jeszcze raz dzięki

    Dodano po 3 [minuty]:

    źle Ciebie zrozumiałem. Myślałem że w przerwaniu od UDRE wyłączasz nadawanie jeżeli już cały bufor został by wysłany, co było by błędem.
  • #14 8687435
    adambehnke
    Poziom 24  
    Może podepnę się do tematu , gdyż też walczę z rs485. Czy i w Bascomie można by w taki sposób sterować kierunkiem transmisji? Bo bardzo by to upraszczało sterowanie i nie musiałbym dobierać opóźnienia w przełączaniu MAX-a na odbiór.


    edit: W sumie to chyba zadałem głupie pytanie. Przecież co za różnica czy Bascom czy C. Przerwania są te same .
  • Pomocny post
    #15 8687506
    mirekk36
    Poziom 42  
    Ja już za mało pamiętam Bascoma żeby tu podpowiedzieć. Ale na pewno można na własny sposób oprogramować przerwania - tyle że to będzie niejako wyważanie głową drzwi bo z jednej strony Bascom ma fajnie napisaną sprzętową obsługę RS232 tylko trzeba umiec ją wykorzystać.

    Ale kurczę zaglądam teraz do HELP'a bascoma a tam jak byk masz napisane:

    Cytat:

    Remarks

    pin
    The name of the PORT pin that is used to control the direction of an RS-485 driver.

    mode
    SET or RESET




    Use PRINT or PRINT0 for the first serial port. Use PRINT1 for the second serial port.



    When you use RS-485 half duplex communication you need a pin for the direction of the data. The CONFIG PRINT automates the manual setting/resetting. It will either SET or RESET the logic level of the specified pin before data is printed with the BASCOM print routines. After the data is sent, it will inverse the pin so it goes into receive mode.

    You need to set the direction of the used pin to output mode yourself.


    Czyli że możesz powierzyć Bascomowi w pełni automatyczną kontrolę nadajnika/odbiornika ..... po co więc sam jakoś kombinujesz z jakimiś dziwnymi opóźnieniami ???
  • #16 8687537
    adambehnke
    Poziom 24  
    Racja! Dzięki! Właśnie zobaczyłem w Bascomie 2.0 i jego nowym helpie piękny przykład obsługi RS485 wraz z automatycznym sterowaniem kierunkiem transmisji.

    edit:

    Automatyczne sterowanie działa rewelacyjnie i znacznie upraszcza kod.
    Dla potomnych:

    Config Print0 = Portd.2 , Mode = Set                        ' use portd.2 for the direction
    Rs485dir Alias Portd.2
    Config Rs485dir = Output
    Rs485dir = 0   ' go to receive mode
  • #17 8687783
    kubus_puchatek
    Poziom 18  
    Kolego.
    Zacznij od schematu i układu płytki PCB.
    skoro nawet WDT nie daje rady to tam leży problem.
  • #18 8687817
    hotdog
    Poziom 26  
    kubus_puchatek napisał:
    Kolego.
    Zacznij od schematu i układu płytki PCB.
    skoro nawet WDT nie daje rady to tam leży problem.


    Przeczytaj cały temat...
  • #19 8690673
    hotdog
    Poziom 26  
    mirekk36 dzięki serdeczne za przypomnienie o przerwaniu UDRE. Uratowało mi ono życie. Program działa już od ponad doby bez przerwy. W tym czasie wykonał około 100k odczytań z termometrów i 100k zapytań o stan urządzenia. Komunikację zrealizowałem dokładnie tak jak napisałem wcześniej, czyli trochę inaczej niż Ty.

    Trochę kodu:
    /*
     * Sends packet via UART. If packet is already sending it breaks and returns
     * number of bytes left to send. If success it returns 0.
     */
    uint8_t ProtocolSendPacket(uint16_t reciverAdress)
    {
    	if (bytesToSend > 0)
    	{
    		return bytesToSend;
    	}
    	memcpy(uartBufferOut + PF_DEST_ADDRESS,&reciverAdress,sizeof(uint16_t));
    	memcpy(uartBufferOut + PF_SOURCE_ADDRESS,&MyAddress,sizeof(uint16_t));
    	uartBufferOut[PF_CRC] = CountCRC(0x00,uartBufferOut,PF_CRC);
    	uartBufferOut[PF_DATA + uartBufferOut[PF_LENGTH]] = CountCRC(uartBufferOut[PF_CRC],uartBufferOut + PF_DATA,uartBufferOut[PF_LENGTH]);
    	bytesToSend = PF_DATA + 1 + uartBufferOut[PF_LENGTH];
    	ptrByteToSend = uartBufferOut;
    	LED_RXTX_BLINK();
    	RS485_SET_TRANSMIT();
    	UDR = PREAMBLE;
    	UDRE_IRQ_ENABLE();
    	return 0;
    }
    
    /*
     * Interrupt executed after UART buffer out is empty, and ready to write data.
     */
    ISR(USART_UDRE_vect)
    {
    	LED_RXTX_BLINK();
    	if (bytesToSend < 1)
    	{
    		UDRE_IRQ_DISABLE();
    		TXC_IRQ_ENABLE();
    		return;
    	}
    	UDR = *ptrByteToSend++;
    	bytesToSend--;
    }
    
    
    /*
     * Interrupt executed after finish of transmition data via UART.
     */
    ISR(USART_TXC_vect)
    {
    	RS485_SET_RECIVE();
    	TXC_IRQ_DISABLE();
    }


    Dzięki i pozdrawiam
  • #20 8690819
    mirekk36
    Poziom 42  
    No a przypomnij sobie co już chciałeś kombinować ;)

    hotdog napisał:

    W sumie chce już pomału dołożyć oddzielny reset wykonany z attiny13. Główny uC będzie puszczał kwadrat na jakimś porcie. Jak tiny nie wykryje zmiany przez kilka us, to ściągnie reset w dół.


    Tak to bywa, że doszukujemy się nieraz problemów w sprzęcie czy siłach nadprzyrodzonych a na końcu okazuje się, że to po prostu babol w programie ;)

    A odnośnie twojego sposobu tego troszkę zmienionego - pewnie, że może być. Ty po prostu włączasz nadajnik na czas wysyłania całej swojej ramki, a żonglujesz tylko włączaniem/wyłączaniem przerwania TXC , ja natomiast załączam i wyłączam nadajnik tylko na czas pojedynczego wysyłanego znaku czyli ja żongluję linią nadajnika DE. Jedno i drugie ma prawo działać ;)
  • #21 8691054
    hotdog
    Poziom 26  
    Byłem trochę zdesperowany. Teraz wiem że nie powinienem wykorzystywać przerwania TXC bo w sumie spowalniam transmisję nie potrzebnie, oraz ono do tego nie zostało zaprojektowane.

    Ale to i tak nie zmienia faktu, że program merytorycznie był ok, i dalej nie wiem gdzie w nim był błąd. Ogólnie pierwszy raz wykorzystywałem go z kwarcem 16MHz i pierwszy raz z prędkością 9600. Może te zależności czasowe powodowały że czasem gdzieś tam coś szło nie tak jak sobie zaplanowałem.

    Tak sobie teoretyzuje nad Twoim rozwiązaniem... Testowałeś je na różnych bound'ach i różnych freq uC?

    Jak dobrze rozumiem to ustawiasz ZAWSZE RS485 na nadajnik w przerwaniu od UDRE przed zapisaniem kolejnego bajtu do bufora (jeżeli koniec bufora nie ustawiasz). Następnie w TXC ustawiasz RS485 na odbiornik. Niby to brzmi ok, tym bardziej że jest to przetestowane rozwiązanie (moje niby też było). Z mojej akutalnej wiedzy wnioskuję że przerwanie od UDRE wykona się od razu 2x po włączeniu (jeżeli znak był nie nadawany w danym czasie), a to dlatego że najpierw wpiszesz 1 bajt do UDR, ten od razu pójdzie do shiftera i zaraz przerwanie wykona się drugi raz (a dane dalej są w shifterze). Co za tym idzie 2 razy ustawisz maxa na nadajnik, a na odbiornik przestawisz po zakończeniu transmisji 1 znaku czyli teoretycznie w trakcie lub przed nadaniem 2 znaku. Ale wtedy masz już bufor pusty i uruchamia się znowu przerwanie UDRE w którym ustawisz maxa na transmisję ale już de facto dla 3 znaku. A chyba Tobie o to nie chodziło? Przy ostatnim bajcie coś się może chyba zgubić?

    A może się gdzieś mylę w tym co napisałem wyżej?

    Pozdro i jeszcze raz dzięki za świeże spojrzenie na mój kod.
  • #22 8691431
    mirekk36
    Poziom 42  
    No tak sobie aż jeszcze raz zerknąłem w notę PDF żeby sprawdzić to co piszesz:

    hotdog napisał:
    .....Z mojej akutalnej wiedzy wnioskuję że przerwanie od UDRE wykona się od razu 2x po włączeniu (jeżeli znak był nie nadawany w danym czasie), a to dlatego że najpierw wpiszesz 1 bajt do UDR, ten od razu pójdzie do shiftera i zaraz przerwanie wykona się drugi raz (a dane dalej są w shifterze). Co za tym idzie 2 razy ustawisz maxa na nadajnik, a na odbiornik przestawisz po zakończeniu transmisji 1 znaku czyli teoretycznie w trakcie lub przed nadaniem 2 znaku. Ale wtedy masz już bufor pusty i uruchamia się znowu przerwanie UDRE w którym ustawisz maxa na transmisję ale już de facto dla 3 znaku. A chyba Tobie o to nie chodziło? Przy ostatnim bajcie coś się może chyba zgubić?


    tzn w nocie jest wyraźnie napisane, że:

    Cytat:

    The Transmit Complete (TXCn) Flag bit is set one when the entire frame in the Transmit Shift
    Register has been shifted out and there are no new data currently present in the transmit buffer.


    czyli wynika z tego, że i przy trzecim bajcie nic się nie może zgubić wg mnie.

    No ale po takiej analizie masz rację, że nie o to do końca mi chodziło bo jednak nadajnik nie będzie się przełączał na każdy znak ale co 2 albo 3. Zatem generalnie takie rozwiązanie jak ty zrobiłeś jest lepsze poniekąd.

    Tyle, że ja zdecydowanie wolę załączać nadajnik tuż przed wpisaniem bajtu do bufora UDR i wtedy ładnie dzieje mi się to w przerwaniach - a podstawowa funkcja wysyłająca pojednyczy znak do bufora cyklicznego musi już tylko załączyć UDRIE. Ale to szczegół w zasadzie ;)

    Dodano po 5 [minuty]:

    a jednak ! .... kurczę okazuje się że korzystniej jest załączać nadajnik na dłuższy okres czyli na cały czas nadawania własnej ramki zamiast tak jak robiłem wcześniej na pojedyncze bajty..... okazuje się bowiem, że przy można jeszcze bardziej zmniejszyć czas pomiędzy wysyłaniem/odbiorem ramek do poszczególnych Slave tak żeby nie mieć FrameError'ów jeszcze.

    Zatem ja też dziękuję za zwrócenie uwagi ;) .... nie ma to jak porządna dyskusja ;)
  • #23 8698197
    hotdog
    Poziom 26  
    W sumie jak miałeś napisany tak kod, że zawsze zdążyłeś dodać nowy bajt do bufora przed zakończeniem transmisji poprzedniego to przerwanie od TXC nie wykonało się ani razu (bo bufor nigdy nie był pusty przed zakończeniem transmisji bajta z shiftera). Dopiero po zakończeniu transmisji całego pakietu. Czyli Twój kod działał tak jak mój aktualny... mniej więcej.

    Fajnie że się oboje czegoś nauczyliśmy, a mi udało się rozwiązać problem. Jeszcze raz dzięki.

    Pozdrawiam
REKLAMA