Debug: utläsning av sekvenser *uppdaterat*

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Debug: utläsning av sekvenser *uppdaterat*

Inlägg av Icecap »

Ibland har man ett nästan fungerande system och man vill se vad som händer vissa saker, vilka sekvenser osv.

Jag ser oftast till att få en fungerande seriell port på ett system, det är mycket bra för att skriva ut meddelanden och värden i debugsyfte. Men jag försöker oftast att använda interruptstyrd utskrift varför en debug-utskrift inifrån en ISR kan låsa allt. Inte bra!

Alltså behövs en möjlighet att samla ihop sekvenserna i någon buffer och sedan skriva ut som vid lämpligt tillfälle. Och det har jag sedan gjort vid att deklarera:

Kod: Markera allt

#define USE_SEQUENCE true
#if USE_SEQUENCE
struct
  {
  _UWORD Input, Output, Intermediate;
  _UBYTE Filled;
  _UBYTE Buffer[100];
  } Sequence;

void Sequence_Initiate(void)
  {
  Sequence.Input  = 0;
  Sequence.Output = 0;
  Sequence.Filled = false;
  }

int Sequence_Add(_UBYTE Data)
  {
  if(Sequence.Filled && (Sequence.Input == Sequence.Output)) return(false);
  Sequence.Filled = true;
  Sequence.Buffer[Sequence.Input++] = Data;
  if(Sequence.Input >= sizeof(Sequence.Buffer)) Sequence.Input = 0;
  return(true);
  }

int Sequence_Check(void)
  { // Something to fetch?
  if(Sequence.Filled) return(true);
  return(false);
  }

_UBYTE Sequence_Get(void)
  {
  _UBYTE Data;
  if(!Sequence_Check()) return(false);
  Data = Sequence.Buffer[Sequence.Output++];
  if(Sequence.Output >= sizeof(Sequence.Buffer)) Sequence.Output = 0;
  if(Sequence.Output == Sequence.Input) Sequence.Filled = false;
  return(Data);
  }
#endif
I main-loop lägger jag då:

Kod: Markera allt

#if USE_SEQUENCE
    if(Sequence_Check())
      {
      // Format printout as required
      sprintf(Buffer, "\rSeq:%3u  \r\n", Sequence_Get()); RS232_B_Send_Buffer((_UBYTE*)Buffer);
      }
#endif // USE_SEQUENCE
och de ställen jag vill lägga in en "har varit här"-markering:
#if USE_SEQUENCE
Sequence_Add(18); // Värdet ska såklart variera från punkt till punkt!
#endif // USE_SEQUENCE

Jag använder en byte för dessa koder då det räcker fint till mig, man kan såklart utöka om man behöver.

Det är i grunden bara en cirkulär buffer, mycket lik den jag använder vid interruptstyrd utskrift. Och nej, det är inte epokgörande - men det kan vara ett trevligt sätt att få koll på att t.ex. ett samspel av hårdvaru-interrupt samspelar rätt och man kan få en idé om var det går fel.

EDIT: Ser att första utläsning blir fel. Får fixa rätt version sen - men principen är OK tycker jag.

EDIT igen: nu fungerar mjukvaran rätt.
Senast redigerad av Icecap 4 april 2014, 12:03:56, redigerad totalt 1 gång.
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Re: Debug: utlösning av sekvenser *uppdaterat*

Inlägg av vfr »

Håller med Icecap om att en debugserieport för utskrifter är väldigt värdefullt i vissa lägen. För det första naturligtvis om man inte har någon riktig debugger med möjlighet att sätta brytpunkter. Då kanske det är enda möjligheten. Men även med en riktig debugger så hamnar man i situationer där man t.ex vill se tidssamband mellan olika saker. Då är brytpunkter helt oanvändbart då det stoppar tiden.

Min lösning har också varit att skapa en debugport, men min lösning är lite annorlunda. Jag brukar istället göra en så tight bitbang-rutin som möjligt och slå av avbrottet under tiden den skriver ett tecken. Kör man då ett antal hundra kbit/s så blir avstängningtiderna ganska korta och det kan t.o.m gå att ha utskrifter i avbrottrutiner. T.ex så kör jag i 920kbit/s bitbang på en PIC och sedan ut till en FTDI som är kopplad till PC:n. En enda utgång på mikrokontrollern går åt till detta.

Det var inte meningen att kapa Icecaps tråd utan mera att hålla med om vikten av en sådan funktion och visa på att det finns flera lösningar som kan vara bra för olika saker.
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Debug: utlösning av sekvenser *uppdaterat*

Inlägg av Icecap »

Håller med vfr. Det viktiga är att få ut intern information och visst, en ICD kan vara guld värd - men som mitt nuvarande problem är hårdvaratimingen utan betydelse, det är hur sekvensen av interrupts och bits hänger ihop som är av vikt och därför skapade jag denna sekvens-avläsning.

Ibland är timingen av stor vikt (t.ex. 1-Wire® kommunikation) och då är en pinna och ett oscilloskop av stort värde.

Alla sätt är bra förutom de dåliga!

En bra grej är att designa enheter så att man har ett par pinna i överskott. Där monterar man LED med olika färger, underbart för debug. För min del är det oftast en "kommer den hit alls?" fråga och den kan enkelt besvaras med en LED på en pinne. Använder man den som:

Kod: Markera allt

void Någon_Interrupt_ISR(void)
  {
  LED = true;
  ... // Do the ISR-stuff
  LED = false;
  }
då kan man se hur lång tid ISR'n tar, om den inte nollställs för att en bit hänger osv. Fungerar mycket bra med ett oscilloskop som tillbehör.

På mitt nuvarande projekt har jag en röd, gul, grön och blå LED på och använder dom som debug-lampor för tillfället. När all hårdvara är kontaktbar kommer jag att använda dom som status-indikeringar, den blåa ska dubbelblinka som "I'm alive!" och de andra ska aktiveras beroende på vilken funktion kortet har.
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Re: Debug: utlösning av sekvenser *uppdaterat*

Inlägg av mri »

Jag har använt samma "buffer" system som Icecap för att debugga interrupt händelseförlopp var jag inte ville ha nån extra fördröjning från själva debug koden. Jag tycker dock att Icecaps ringbuffer är, för ändamålet, dåligt implementerad. Genom att endast ha en head och tail pekare kan man bygga en ring som är "threadsafe" för single producer single consumer, utan att man behöver stänga av interrupt vid access i ringen. Som det är nu pillar både Add() och Get() på samma variabel.

På senare tid har jag på kraftigare MCU'n använt DMA för att skyffla debug data till debug serieporten. Det är mycket trevligt.
Skriv svar