AVR + proste SPI w C

May 11, 2006 14 Replies

Witam chcialem sobie odczytac 14 kolejnych bitow na wejsciu uC taktujac uklad zewnetrzny sygnalem SCK. Chodzi tutaj o magistrale SPI. Uklad ten posiada 3 szyny komunikacyjne SCK, CS, SO. W uC niestety nie jest on podlaczony do sprzetowego SPI tylko do portow PD5,PD6,PD7 uC.



Napisalem prosty programik (byc moze zly :)) ktory ma mi te bity pokazac. Zmienna Shift puki co nic nie robi, oraz wiem ze do zmiennej typu char da sie wsadzic tylko 8 bitow. Chodzi o to ze na uarcie widze tylko:



01111111111111 co jest nie prawda poniewaz przedostatni bit zawsze powinien byc zerem. Uklad zaczyna wysylanie danych po CS -> L i nowy bit pokazuje sie po kazdym opadajacym zboczu sygnalu.


#define SPI_PULSE { PORTD &= ~_BV(PD7); PORTD |= _BV(PD7); } //zostaw wysoki do czasu nastepnego pulse.



#define SOIN { DDRD &= ~_BV(PD5); PORTD |= _BV(PD5); } //ustaw jako wejscie, wlacz pullup.



#define CSLOW { DDRD |= _BV(PD6); PORTD &= ~_BV(PD6); } //wyjscie low #define CSHIGH { DDRD |= _BV(PD6); PORTD |= _BV(PD6); } //wyjscie high



unsigned char rspi(void) { uart_puts("-"); register unsigned int BitCnt = 14; register unsigned char Shift; SOIN; CSLOW; do { if(bit_is_set(PORTD,PIND5)) { uart_puts("1"); }else{ uart_puts("0"); } SPI_PULSE; } while (--BitCnt); CSHIGH; return(Shift); }


co robie zle ze to SPI mi nie dziala? wydaje sie proste zrozumienie tego protokolu... ktos mi pomoze?



Pzdr, Mario.


Dnia 11-05-2006 o 09:56:43 angel snipped-for-privacy@REMMEszas.uk.to> napisał:

Nie za krótki ten impuls? Dodaj przynajmniej kilka nop-ów. Poza tym nie inicjalizujesz PD7 jako wyjścia.

Poprawilem nieco program:

#define SPI_INIT { DDRD |= _BV(7); DDRD |= _BV(6); DDRD &= ~_BV(5); /*PORTD |= _BV(5);*/ }

#define SPI_PULSE { PORTD &= ~_BV(7); delay_us(1); PORTD |= _BV(7); }

#define READ_MSO ( PIND & ( 1 << 5))

#define CSLOW { PORTD &= ~_BV(6); } #define CSHIGH { PORTD |= _BV(6); }

unsigned char rspi(void) { uart_puts("-"); SPI_INIT; register unsigned int BitCnt = 14; register unsigned char Shift; CSLOW; do { if(READ_MSO) { uart_puts("1"); }else{ uart_puts("0"); } SPI_PULSE; } while (--BitCnt); CSHIGH; delay_us(10); return(Shift); }

ale dalej nie dziala :( zwraca mi bity 0, jak uruchomilem go na debbugerze w Avr studio i klikam PIND5 (zaznaczony co powinno dac 1 na PD5) program nie reaguje i ciagle zwraca 0. Czy zle czytam port? Czy w debuggerze to nie wyjdzie?

m.

angel snipped-for-privacy@REMMEszas.uk.to> napisał(a):

Nie wiem co Ty za pin klikasz , bo u mnie toto działa.

P.

W sensie moj program dzia³a, czy czytanie pinu? Mi nie dziala ani na zywo ani w debugerze. Klikam dokladnie w linijce PIND portu D trzecia kostke od lewej, zapala sie ona na czarno (0x20) wartosc hex PIND po operacji, a petla przejezdza i zachowuje sie jakby nie bylo ustawionego bitu.

M.

angel snipped-for-privacy@REMMEszas.uk.to> napisał(a):

Dziwne :( Może symulator sumuluje innego proca , a Ty kompilujesz na innego ? Spróbuje tego:

#include <avr/io.h> //ATMega32 #define F_CPU 1000000UL #include <util/delay.h>

#define SPI_INIT { DDRD |= _BV(7); DDRD |= _BV(6); DDRD &= ~_BV(5); /*PORTD |= _BV(5);*/ }

#define SPI_PULSE { PORTD &= ~_BV(7); _delay_us(1); PORTD |= _BV(7); }

#define READ_MSO ( PIND & ( 1 << 5))

#define CSLOW { PORTD &= ~_BV(6); } #define CSHIGH { PORTD |= _BV(6); }

void uart_puts(char *g) //ot,żeby był ;) {

*g>>=1; }

int main(void) { uart_puts("-"); SPI_INIT; register unsigned int BitCnt = 14; register unsigned char Shift; CSLOW; do { if(READ_MSO) { uart_puts("1"); }else{ uart_puts("0"); } SPI_PULSE; } while (--BitCnt);

return(0); }

P.

Masz AVR Studio 4.12 z SP2? Bo kurcze, w innym moim programie podobny fragment zachowuje sie dokladnie tak samo, z kolei "na zywo" dziala. Wydaje mi sie, ze w AVR Studio jest blad w debuggerze. Po kliknieciu na bit w PIN zmienia sie prawidlowo wartosc hex, kratka zaczernia, ale program odczytuje taki bit jako 0, a nie 1. Mozecie to potwierdzic?

Tak, mam 4.12 z SP2.

Docelowo program wyglada tak:

#define SPI_INIT { DDRD |= _BV(7); DDRD |= _BV(6); DDRD &= ~_BV(5); PORTD |= _BV(5); } //2 wyjscia , 1 wejscie dla SO + pullup

#define SPI_PULSE_H { PORTD |= _BV(7); } #define SPI_PULSE_L { PORTD &= ~_BV(7); }

#define READ_MSO ( PIND & ( 1 << PD5))

#define CSLOW { PORTD &= ~_BV(6); } #define CSHIGH { PORTD |= _BV(6); }

unsigned char rspi(void) { uart_puts("-"); register unsigned int BitCnt = 14; register unsigned int w = 0; register unsigned char Shift; CSLOW; asm volatile ("nop"); do { SPI_PULSE_L; asm volatile ("nop");

if(READ_MSO) w++;

SPI_PULSE_H; asm volatile ("nop"); } while (--BitCnt); CSHIGH; uart_puti(w); return(Shift); }

jako wynik dostaje 14, co oznacza ze wszystkie odebrane dane to 1dynki. Jak wylacze pullup dla pind5 dostaje wynik 0 czyli same zera. Czy SPI uzywa pullupow? Ten uklad z ktorym sie komunikuje uzywa sprzetowego SPI i jest domyslnie jako slave. Czemu nie moge go przeczytac? Zmiana czasow trwania zboczy poprzez dodanie delay_us nic nie daje... ciagle nie dziala. Skoro to uC narzuca wygnal taktujacy to w czym jest problem? Sprawdzalem woltomierzem CS ustawia sie na low poprawnie, taktu zegara nie jestem w stanie zlapac :))

M.

Czy na porcie D musze cos wylaczac zeby byl on normalnym portem w atmega32 ???

Uda³o mi sie uruchomiæ uk³ad ale tylko na chwile. Zaczal dzialac samoistnie, po czym samoistnie przestal. Moge natomiast zmusic go do pracy odlaczajac mu zasilanie (tak wlasnie!) Na wejsciu siedzi C 4700uF ktory potrafi zasilic uklad przez jakies 4s przerwy w zasilaniu. W momencie kiedy wylaczam zasilanie ostatni ciag jaki pokazuje sie na UART to 00001110010001 i nie jest to przypadkowy string, tylko wlasnie dane ktorych oczekuje. Polaczenia galwaniczne posprawdzalem, wszystko jest OK, o co moze chodzic?

M.

angel snipped-for-privacy@REMMEszas.uk.to> napisa³

Poziomy napiec? Masz moze rozne napiecia zasilania procesora i obslugiwanego scalaczka?

JJJK

Dnia Fri, 12 May 2006 11:21:59 +0200, angel napisał(a):

A zwykłe "blinkanie" diodą czy transmisja stałego znaku na UART działa? Podłączył kolega analogowe zasilanie? Kondensatory odsprzęgające przy procku są? Zasilacz nie sieje jakimiś śmieciami?

Uff! ;) Marcin Stanisz

Wszystko siedzi na jednej plytce za LM7805. Zrodlo zasilania jest jedno.

M.

Tak, zarowno staly znak ("-") oznaczajacy poczatek transmisji jak i cala reszta przez uart ida... tyle ze w momencie kiedy nie dziala dostaje wynik:

-111111111111111 a kiedy dziala (przykladowo) -00000001110111. Migajaca dioda jest w ukladzie dla testu i miga rownomiernie az milo, jest tez wyswietlacz lcd ktory nie ma zadnych problemow. Vcc,GND,AVcc sa podlaczone AVcc i Vcc sa zwarte ze soba poniewaz nie uzywam ADC. Kondensatorkow kilka 100n przy scalakach dalem.

Moze przez ten duzy C na wejsciu mam problemy? powoduje niestabilna prace podczas ladowania...?

M.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required