Greg(G.Kasprowicz)
Guest
Fri Oct 06, 2006 8:37 pm
Hej
mam taki problem z kompilatorem AVR GCC - na moj gust zglupial lub pewnei
robie cos zle.
jest takie powiedzenie, jesli twierdzisz ze kompilator jest glupi - idz
spac.
ale nie w tym rzecz.
mam wynik pomiaru w postaci liczby 32 bit (wynik z ukladu TCD pomiaru czasu
z rozdzielczoscia 7ps(sic!))
i potrzebuje go przemnozyc przez stala 7.629453
nie chce uzywac arytmetyki zmiennoprzecinkowej, zreszta z jakis powodow ona
tez nie dziala.
wersja zmiennoprzecinkowa
float calc_temp;
uint32_t calc_temp1;
calc_temp1 = TDC_Read(0);
if (calc_temp1 != 0xFFFFFFFF) //overrange detection
{
calc_temp = (calc_temp1*7.629453);
tlcd_write_U32((U32)calc_temp);
tlcd_write_string("ps");
}
else tlcd_write_string(" OVR ");
no i wynik nie dosc ze jest bez sensu to zawija sie gdzies przy 16 bitach,
ale to musze dokaldneij sprawdzic
wersja integer:
uint64_t calc_temp;
U32 calc_temp1;
calc_temp1 = TDC_Read(0);
if (calc_temp1 != 0xFFFFFFFF) //overrange detection
{
calc_temp = (calc_temp1*7629453UL)/1000000UL; //result in ps
tlcd_write_U32((U32)calc_temp);
tlcd_write_string("ps");
}
else tlcd_write_string(" OVR ");
Wynik wydaje zawijac sie gdzies na 16 bitach lub wczesniej.
nie pomaga zadeklarowanie liczb jako 1000000ULL, jedyny efekt uboczny to
taki ze objetosc kodu zwieksza sie o 4KB - widac kompilator wlacza
biblioteki 64bit??
o robie zle? pewnie znow sie okaze ze gdzies do zmiennej powinienem byl
dodac jakas literke...
z innej beczki:
czy spotkaliscie sie z bibliotekami w C konwerujacymi np U32 na BCD?
napisalem sobie wlasne,ale na pewno nie sa optymalne jesli chodzi o kod, a
pewnie istnieja gdzies eleganckie napisane w ASM...
Jarosław Grolik
Guest
Fri Oct 06, 2006 8:55 pm
Witam.
Użytkownik "Greg(G.Kasprowicz)" <gkasprow@gmail.com> napisał w wiadomości
news:eg6er3$dk$1@news.onet.pl...
Quote:
Hej
mam taki problem z kompilatorem AVR GCC - na moj gust zglupial lub pewnei
robie cos zle.
jest takie powiedzenie, jesli twierdzisz ze kompilator jest glupi - idz
spac.
A jesteś pewien, że TDC daje Ci to czego oczekujesz ?
Na którym TDC pracujesz ? Acam ? MSC ? jeszcze inne ?
Ja czasami dostaje dziwne wyniki z TDC GP1
Pozdrawiam
Jarek Grolik
Greg(G.Kasprowicz)
Guest
Fri Oct 06, 2006 9:12 pm
Quote:
A jesteś pewien, że TDC daje Ci to czego oczekujesz ?
Na którym TDC pracujesz ? Acam ? MSC ? jeszcze inne ?
Ja czasami dostaje dziwne wyniki z TDC GP1
tak, TDC GP1 - ogldam w hexie i jest idealnie.
Obok porownuje ze zgrubnym odczytem z oscyloskopu
ten sam problem mam z odczytem czasomierza zaimplementowanego w FPGA - chce
przemnozyc liczbe 32bit przez 6.66666ns, i identyczny problem..
BTW: do czego uzywasz GP1?
- ja do pomiaru szeroksoci impulsow z akceleratora oraz dlugosci impulsow
laserowych w dalmierzach.
mk
Guest
Fri Oct 06, 2006 10:14 pm
Newsuser "Greg(G.Kasprowicz)" wrote:
Quote:
jest takie powiedzenie, jesli twierdzisz ze kompilator jest glupi - idz
spac.
Oj zdarza się, że kompilator robi psikusy.
Kto miał do czynienia z MSVC6 ten wie :-)
Quote:
wersja integer:
uint64_t calc_temp;
U32 calc_temp1;
calc_temp1 = TDC_Read(0);
if (calc_temp1 != 0xFFFFFFFF) //overrange detection
{
calc_temp = (calc_temp1*7629453UL)/1000000UL; //result in ps
W ostatniej linii prowadzisz obliczenia na liczbach 32 bitowych. Dopiero
przy przypisaniu następuje konwersja na liczbę 64 bitową. To za późno.
pzdr
mk
Adam Dybkowski
Guest
Fri Oct 06, 2006 10:51 pm
Greg(G.Kasprowicz) napisał(a):
Quote:
mam wynik pomiaru w postaci liczby 32 bit
[...]
i potrzebuje go przemnozyc przez stala 7.629453
Quote:
uint64_t calc_temp;
U32 calc_temp1;
calc_temp1 = TDC_Read(0);
if (calc_temp1 != 0xFFFFFFFF) //overrange detection
{
calc_temp = (calc_temp1*7629453UL)/1000000UL; //result in ps
Musisz pamiętać, że sposób obliczania jest niejako narzucony przez
pierwszą operację. Czyli w powyższym mnożeniu liczby 32-bitowej
calc_temp1 przez 32-bitową stałą 7629453UL już masz problem - będzie
przepełnienie i obcięcie. Potem dzielisz to przez kolejną 32-bitową
stałą 1000000UL i nic sensownego z tego działania nie pozostanie.
Powinno zadziałać takie rozwiązanie (sprawdź):
uint64_t a, b, c;
a = TDC_Read(0);
b = (a * 7629453ULL) / 1000000ULL;
Jeżeli a jest 32-bitowe to przed mnożeniem zrzutuj je na 64 bity:
b = (uint64_t) a * 76294...
I jak poszło? Pamiętaj, że stałe 64-bitowe w AVR wymagają dopisku LL / ULL.
--
Adam Dybkowski
http://www.amwaw.edu.pl/~adybkows/
Uwaga: przed wysłaniem do mnie maila usuń cyfry z adresu.
Greg(G.Kasprowicz)
Guest
Fri Oct 06, 2006 11:14 pm
Quote:
Musisz pamiętać, że sposób obliczania jest niejako narzucony przez
pierwszą operację. Czyli w powyższym mnożeniu liczby 32-bitowej calc_temp1
przez 32-bitową stałą 7629453UL już masz problem - będzie przepełnienie i
obcięcie. Potem dzielisz to przez kolejną 32-bitową stałą 1000000UL i nic
sensownego z tego działania nie pozostanie.
tak tez podejrzewalem. dlatego probowalem z tym ULL, tyle ze troche widac za
pozno.
Quote:
Powinno zadziałać takie rozwiązanie (sprawdź):
uint64_t a, b, c;
a = TDC_Read(0);
b = (a * 7629453ULL) / 1000000ULL;
Jeżeli a jest 32-bitowe to przed mnożeniem zrzutuj je na 64 bity:
b = (uint64_t) a * 76294...
I jak poszło? Pamiętaj, że stałe 64-bitowe w AVR wymagają dopisku LL /
ULL.
tylko teraz, dlaczego dlugosc kodu wzrasta o te 4kB? az tyle zajmuja
procedury mnozenia 64 bit?
w asemblerze 8051 mnozylem nawet liczby 96bit i zajmowalo kilkaset Bajtow.
Czy da sie jakos ograniczyc ilosc tego marnowanego kodu?
Adam Dybkowski
Guest
Fri Oct 06, 2006 11:27 pm
Greg(G.Kasprowicz) napisał(a):
Quote:
Jeżeli a jest 32-bitowe to przed mnożeniem zrzutuj je na 64 bity:
b = (uint64_t) a * 76294...
tylko teraz, dlaczego dlugosc kodu wzrasta o te 4kB? az tyle zajmuja
procedury mnozenia 64 bit?
Obejrzyj w mapie linkera (i ew. listingu po deasemblacji) jakie funkcje
zajęły najwięcej. Mnożenie 64-bitowe bez problemu napiszesz na kolanie i
zajmie mniej niż kilkaset bajtów. Albo ściągnij gotowe z Sieci.
--
Adam Dybkowski
http://www.amwaw.edu.pl/~adybkows/
Uwaga: przed wysłaniem do mnie maila usuń cyfry z adresu.
J.F.
Guest
Sat Oct 07, 2006 7:33 am
On Sat, 07 Oct 2006 00:51:00 +0200, Adam Dybkowski wrote:
Quote:
Greg(G.Kasprowicz) napisał(a):
calc_temp = (calc_temp1*7629453UL)/1000000UL; //result in ps
Musisz pamiętać, że sposób obliczania jest niejako narzucony przez
pierwszą operację. Czyli w powyższym mnożeniu liczby 32-bitowej
calc_temp1 przez 32-bitową stałą 7629453UL już masz problem - będzie
przepełnienie i obcięcie.
No i jak chcesz przemnozyc przez 7,629453 to moze szybciej
bedzie przemnozyc przez 32768251121 a potem "podzielic"
przez 2^32
J.
J.F.
Guest
Sat Oct 07, 2006 8:05 am
On Fri, 6 Oct 2006 23:12:54 +0200, Greg(G.Kasprowicz) wrote:
Quote:
ten sam problem mam z odczytem czasomierza zaimplementowanego w FPGA - chce
przemnozyc liczbe 32bit przez 6.66666ns, i identyczny problem..
Hi hi - a duzo masz czasu ?
Bo jesli na jedno wejscie sumatora podasz liczbe, a na drugie jego
wyjscie podzielone przez 4, to po chwili wyjscie narosnie do
we*1.33333(3)
przemnozmy to przez 2, otrzymamy 2.666666(6), pozostaje dodac 4*we.
Glowy nie dam czy wynik bedzie zawsze stabilny, no i przydaloby sie
dla wiekszej dokladnosci najpierw wejscie "przemnozyc" np *8, a na
koniec podzielic/4
Swoja droga byc moze to ma calkiem ladna postac funkcji
zminimalizowanej .. tylko czym ja wygenerowac :-)
J.
Jarosław Grolik
Guest
Sat Oct 07, 2006 9:06 am
Użytkownik "Greg(G.Kasprowicz)" <gkasprow@gmail.com> napisał w wiadomości
news:eg6gsm$5t4$1@news.onet.pl...
Quote:
BTW: do czego uzywasz GP1?
- ja do pomiaru szeroksoci impulsow z akceleratora oraz dlugosci impulsow
laserowych w dalmierzach.
Ja staram się zrobić na nim precyzyjną i szybką hercmiarkę, ale niestety nie
udało mi się z nim dogadać zbyt dokładnie poprzez LPT i teraz będę go wpierw
podpinał pod uC i dopiero do kompa. Używam trybu MB2 i dostaje stabilną
część całkowitą , natomiast FineCount gania w te i we w te. Uprzedzę , że
częstotliwość odniesienia to wzorzec rubidowy

Robię to do pomiarów QCM.
Pozdrawiam
Jarek Grolik
PS: Jak odczytujesz z niego kolejne wyniki z rejestrów 16 bitowych , to CS
jest cały czas aktywny i tylko podajesz kolejne stroby READ , czy też CS
również podnosisz ?
Mógłbyś podrzucić kawałek kodu odpowiedzialnego za inicjalizację i odczyt ?
PS2 : Jest też ciekawy TDC innej firmy. TDC502 nawet chyba lepiej
dopracowany
J.F.
Guest
Sat Oct 07, 2006 9:21 am
On Sat, 07 Oct 2006 10:05:36 +0200, J.F. wrote:
Quote:
Hi hi - a duzo masz czasu ?
Bo jesli na jedno wejscie sumatora podasz liczbe, a na drugie jego
wyjscie podzielone przez 4, to po chwili wyjscie narosnie do
we*1.33333(3)
hi hi - jeszce jedno podobne: - nie dodawac, tylko odejmowac polowe.
Wynik sie ustali na 0.666666(6) .. czyli najpierw przemnozyc przez 10
[jeden sumator].
Quote:
Glowy nie dam czy wynik bedzie zawsze stabilny,
Hm, z sumowaniem chyba bedzie, ten z odemowaniem to nie dam glowy :-)
J.
Greg(G.Kasprowicz)
Guest
Sat Oct 07, 2006 12:15 pm
Quote:
No i jak chcesz przemnozyc przez 7,629453 to moze szybciej
bedzie przemnozyc przez 32768251121 a potem "podzielic"
przez 2^32
tez o tym pomyslalem, bedzie chyba szybciej,skoro i tak juz mnoze, to
odpadnie dzielenie, bo potem tylko wezme starsza czesc
Greg(G.Kasprowicz)
Guest
Sat Oct 07, 2006 12:18 pm
Quote:
Mógłbyś podrzucić kawałek kodu odpowiedzialnego za inicjalizację i odczyt
?
#include "TDC.h"
U32 TDC_RES_0;
U32 TDC_RES_1;
U32 TDC_RES_2;
U32 TDC_RES_3;
U32 TDC_STAT;
U32 TDC_REG_1;
void TDC_setup(void)
{
TDC_Write(addr_TDC_REG_0,TDC_REG0_default);
TDC_Write(addr_TDC_REG_1,TDC_REG1_default);
TDC_Write(addr_TDC_REG_2,TDC_REG2_default);
//TDC_Write(addr_TDC_REG_3,TDC_REG3_default);
//TDC_Write(addr_TDC_REG_4,TDC_REG4_default);
//TDC_Write(addr_TDC_REG_5,TDC_REG5_default);
}
void TDC_command(U8 command)
{
SPCR |= (1<<CPHA); //set SPI in falling edge mode
PORT_TDC |= (1<< SPI_src); // SPI input = TDC
PORT_TDC &= ~(1<<TDC_CSn);
SPDR = command;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
PORT_TDC |= (1<<TDC_CSn);
SPCR &= ~(1<<CPHA); //set SPI in rising edge mode
}
void TDC_Write(U8 reg,U32 val)
{
SPCR |= (1<<CPHA); //set SPI in falling edge mode
PORT_TDC |= (1<< SPI_src); // SPI input = TDC
PORT_TDC &= ~(1<<TDC_CSn);
SPDR = (reg&0x07)|Write_into_address_ADR;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
SPDR = ((val>>16)&0xff);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
SPDR = ((val>>

&0xff);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
SPDR = (val&0xff);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
PORT_TDC |= (1<<TDC_CSn);
SPCR &= ~(1<<CPHA); //set SPI in rising edge mode
}
U32 TDC_Read(U8 reg)
{
SPCR |= (1<<CPHA); //set SPI in falling edge mode
U32 temp,temp1;
PORT_TDC |= (1<< SPI_src); // SPI input = TDC
PORT_TDC &= ~(1<<TDC_CSn);
SPDR = (reg&0x07)|Read_from_address_ADR;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
SPDR = (0x00);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
temp1 = SPDR;
temp = temp1<<24;
SPDR = (0x00);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
temp1 = SPDR;
temp|= temp1<<16;
SPDR = (0x00);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
temp1 = SPDR;
temp|= temp1<<8;
SPDR = (0x00);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
temp|= SPDR;
PORT_TDC |= (1<<TDC_CSn);
SPCR &= ~(1<<CPHA); //set SPI in rising edge mode
return temp;
}
U16 TDC_STAT_Read(void)
{
SPCR |= (1<<CPHA); //set SPI in falling edge mode
U16 temp;
PORT_TDC |= (1<< SPI_src); // SPI input = TDC
PORT_TDC &= ~(1<<TDC_CSn);
SPDR = (addr_TDC_STAT)|Read_from_address_ADR;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
SPDR = (0x00);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
temp= SPDR<<8;
SPDR = (0x00);
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
{;}
temp|= SPDR;
PORT_TDC |= (1<<TDC_CSn);
SPCR &= ~(1<<CPHA); //set SPI in rising edge mode
return temp;
}
TDC.h
//TDC register 0 default content
#define NEG_START 0
#define NEG_STOP1 0
#define NEG_STOP2 0
#define MRange2 1
#define DisAutoCal 0
#define Calibrate 1
#define SelClkT 1
#define No_FAKE 0
#define TCycle 0
#define PORT 1
// 2 bit
#define START_ClkHS 1
#define ClkHSDiv 0
#define CALRES 0
//4 bit
#define DIV_FIRE 0
#define FIRE 0
//TDC register 0 position
#define pos_NEG_START 0
#define pos_NEG_STOP1 1
#define pos_NEG_STOP2 2
#define pos_MRange2 3
#define pos_DisAutoCal 4
#define pos_Calibrate 5
#define pos_SelClkT 6
#define pos_No_FAKE 7
#define pos_TCycle 8
#define pos_PORT 9
// 2 bit
#define pos_START_ClkHS 10
#define pos_ClkHSDiv 12
#define pos_CALRES 14
//4 bit
#define pos_DIV_FIRE 16
#define pos_FIRE 20
//TDC register definition
//OPCODES
#define Write_into_address_ADR 0b10000000
#define Read_from_address_ADR 0b10110000
#define Init 0b01110000
#define Power_On_Reset 0b01010000
#define Start_Cycle 0b00000001
#define Start_Temp 0b00000010
#define Start_Cal_Resonator 0b00000011
#define Start_Cal_TDC 0b00000100
// 20 16 12 8 4 0
// | | | | | |
#define TDC_REG0_default 0b000000010011011001100010
#define TDC_REG1_default 0b000000010100000100000000
// 20 16 12 8 4 0
// | | | | | |
#define TDC_REG2_default 0b010000000000000000000000
#define TDC_REG3_default 0b001000000000000000000000
// 20 16 12 8 4 0
// | | | | | |
#define TDC_REG4_default 0b001100000000000000000000
#define TDC_REG5_default 0b000000000000000000000000
#define addr_TDC_RES_0 0
#define addr_TDC_RES_1 1
#define addr_TDC_RES_2 2
#define addr_TDC_RES_3 3
#define addr_TDC_STAT 4
#define addr_TDC_REG_0 0
#define addr_TDC_REG_1 1
#define addr_TDC_REG_2 2
#define addr_TDC_REG_3 3
#define addr_TDC_REG_4 4
#define addr_TDC_REG_5 5
void TDC_setup(void);
void TDC_command(U8 command);
void TDC_Write(U8 reg,U32 val);
U32 TDC_Read(U8 reg);
U32 TDC_Read(U8 reg);
U16 TDC_STAT_Read(void);
Greg(G.Kasprowicz)
Guest
Sat Oct 07, 2006 12:19 pm
Quote:
Ja staram się zrobić na nim precyzyjną i szybką hercmiarkę, ale niestety
nie udało mi się z nim dogadać zbyt dokładnie poprzez LPT i teraz będę go
wpierw podpinał pod uC i dopiero do kompa. Używam trybu MB2 i dostaje
stabilną część całkowitą , natomiast FineCount gania w te i we w te.
Uprzedzę , że częstotliwość odniesienia to wzorzec rubidowy

Robię to
do pomiarów QCM.
ja dla odroznienia uzywam trybu 1-szego
interesuje mnei zakres 2ns...1us
kody podalem w innym watku
Greg(G.Kasprowicz)
Guest
Sat Oct 07, 2006 2:48 pm
Quote:
Powinno zadziałać takie rozwiązanie (sprawdź):
uint64_t a, b, c;
a = TDC_Read(0);
b = (a * 7629453ULL) / 1000000ULL;
Jeżeli a jest 32-bitowe to przed mnożeniem zrzutuj je na 64 bity:
b = (uint64_t) a * 76294...
I jak poszło? Pamiętaj, że stałe 64-bitowe w AVR wymagają dopisku LL /
ULL.
dzieki, zadaialalo
jednakze ostatecznie podzielilem wynik pomiaru na 3 zakresy co 1024
i od razu mi wyswietla w ns, us, ms co jest bardziej intuicyjne niz rzad 9
cyfr, z czego i tak 2 ostatnie mrugaj na najwyzszym zakresie (1s range/6ns
bin)