## c't-Projekte - Mailinglisten

[Voriger (Datum)] [Nächster (Datum)] [Voriger (Thread)] [Nächster (Thread)]
[Nach Datum][Nach Thread]

### Re: [ct-bot] CVS-Update

Absender: Markus Hennecke
Datum: Sa, 25.03.2006 14:31:11
In-reply-to: <4424246A.50605@xxxxxxxx>
References: <4422CD39.5090701@xxxxxxxx> <4422ED3F.7010706@xxxxxxxxxxxxxxxxxx> <200603232313.12896.bbe@xxxxxxxx> <4424246A.50605@xxxxxxxx>

    Benjamin Benz wrote:
    > leider musste ich den -Os-Schalter doch nochmal rausnehmen, da auch das
    > Timing des Maussensors durch die Optimierung beeinflusst wird.

    Stimmt, ich hab mir das ganze mal angesehen:

    Als Beispiel nehmen wir einmal den vom Compiler ohne Optimierung
    generierten Code für die Warteschleifen in den Funktionen des Maussensors:

    	...
    **** for (uint8 i = 0; i < 75; i++) asm("nop");

    	std 	Y+3,__zero_reg__	; 2 clocks

    1:	ldd	r24,Y+3			; 2 clocks
    	cpi	r24,lo8(75)		; 1 clock
    	brsh	2			; 1 / 2 clocks

    	nop				; 1 clock

    	ldd	r24,Y+3			; 2 clocks
    	subi	r24,lo8(-(1))		; 1 clock
    	std	Y+3,r24			; 2 clocks
    	rjmp	1b			; 2 clocks

    2:	...

    Also haben wir:
    2 clocks + 75 * 12 clocks + 5 clocks = 907 clocks

    Mit 16 Mhz => ~56,7 us

    Die gleiche Rechnung gilt für mcu/display.c, wo 100 Taktzyklen gewartet
    wird:
    2 + 100 * 12 + 5 = 1207 clocks

    16 MHz => ~75,4 us

    Sollten nun aus der avr-libc die Busy-Wait Routinen (#include
    <util/delay.h>) genutzt werden haben wir aber ein Problem: Mit 16 MHz
    lässt sich maximal 16 us in der _delay_loop_1() warten. Also muß die
    _delay_loop_2() herhalten, hier sind Warteschleifen mit maximal 4 ms
    möglich.

    Allerdings gibt es noch eine ganz andere Schwierigkeit: Wenn der
    Compiler nicht optimiert wird die gesamte Fliesskommaarithmetik, mit der
    der richtige Wert für die Funktionen _delay_ms() bzw. _delay_us()
    berechnet wird als Code eingebunden. Damit hätten wir wiederum
    unterschiedliches Zeitverhalten mit unterschiedlichen
    Optimierungsstufen. Die beiden Funktionen fallen demnach heraus und wir
    müssen _delay_loop_2() nutzen. Diese Schleife verbraucht pro Iteration 4
    Taktzyklen.

    Demnach wäre die Formel für die Delayloop des Maussensors
         4 * x = 907, also x = 227.

    Für das Display, was eine längere Schleife benötigt demnach
         4 * x = 1207, also x = 302.

    Eigentlich sollte das ja ausreichen. Das Display funktioniert so bei mir
    auch ohne Probleme. Allerdings passt das Timing für die Funktionen
    maus_sens_readByte() bzw. maus_sens_writeByte() mit eingeschalteter
    Optimierung auch nicht mehr. Wenn man ins Datenblatt des Sensorchips
    schaut (http://cp.literature.agilent.com/litweb/pdf/5988-9774EN.pdf)
    sieht man in Abbildung 20 das ein Taktzyklus mindestens 500 ns betragen
    muß. Ein Taktzyklus der MCU ist in 62,5 ns abgearbeitet, durch die
    Optimierung stimmt das Timing nicht mehr. Durch einfügen von asm("nop")
    an den betroffenen Stellen in den oben genannten Funktionen konnte ich
    das Timing so verändern, dass der Maussensor bei mir nun mit beiden
    Optimierungsstufen (-O0 und -Os) funktioniert. Da eine minimale Länge
    für einen Taktzyklus angegeben ist sollten die zusätzlich generierten
    Befehle bei ausgeschalteter Optimierung auch keine negativen
    Seiteneffekte haben.

    Mit dem angehängten Patch sollten die beiden Warteschleifen unabhängig
    von den Optimierungseinstellungen des Compilers werden. Ich habe in
    mcu/mouse.c noch einmal einige Parameter an die tatsächliche
    Beschreibung des Datenblatts angepasst. Die beiden Schleifen um 8 Bit zu
    schreiben bzw. zu lesen haben nun den gleichen Aufbau. Die delay
    Funktionen sind per #include <util/delay.h> eingebunden. Ich weiß nicht,
    ob dies mit älteren Versionen der avr-libc geht.

    Der Patch sollte von möglichst vielen getestet werden, bevor er ins CVS
    übernommen wird. Die Timings lassen sich ja immer noch nach oben
    korrigieren.

    MfG
      Markus

    Index: mcu/display.c
    ===================================================================
    RCS file: /ctbot/ct-Bot/mcu/display.c,v
    retrieving revision 1.7
    diff -u -r1.7 display.c
    --- mcu/display.c	24 Mar 2006 18:16:55 -0000	1.7
    +++ mcu/display.c	25 Mar 2006 14:28:41 -0000
    @@ -29,7 +29,7 @@
     #ifdef DISPLAY_AVAILABLE

     #include <avr/io.h>
    -#include <avr/delay.h>
    +#include <util/delay.h>
     #include <stdarg.h>
     #include <stdio.h>

    @@ -96,13 +96,11 @@
      * @param cmd Kommando
      */
     void display_cmd(uint8 cmd){		//ein Kommando cmd an das Display senden
    -	uint8 i;
     	shift_data_out(cmd,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY);
    -	// Enable muss fÃ¼r mind. 450 ns High bleiben, bevor es fallen darf!
    -	// ==> Also mind. 8 Zyklen warten
    -	for (i=0; i<100; i++){
    -	        asm("nop");
    -	}
    +
    +	// ca. 75 us warten
    +	_delay_loop_2(302);
    +
     	DISPLAY_PORT=DPC;	// Alles zurÃ¼ck setzen ==> Fallende Flanke von Enable
     }

    @@ -112,15 +110,12 @@
      * @param data Das Zeichen
      */
     void display_data(char data){ //ein Zeichen aus data in den Displayspeicher schreiben
    -        uint8 i;
    -		shift_data_out(data,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY|DISPLAY_RS);
    -
    -		// Enable muss fÃ¼r mind. 450 ns High bleiben, bevor es fallen darf!
    -		// ==> Also mind. 8 Zyklen warten
    -        for (i=0; i<100; i++){
    -                asm("nop");
    -        }
    -      DISPLAY_PORT=DPC;	// Alles zurÃ¼ck setzen ==> Fallende Flanke von Enable
    +	shift_data_out(data,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY|DISPLAY_RS);
    +
    +	// ca. 75 us warten
    +	_delay_loop_2(302);
    +
    +	DISPLAY_PORT=DPC;	// Alles zurÃ¼ck setzen ==> Fallende Flanke von Enable
     }

     /*!
    Index: mcu/mouse.c
    ===================================================================
    RCS file: /ctbot/ct-Bot/mcu/mouse.c,v
    retrieving revision 1.4
    diff -u -r1.4 mouse.c
    --- mcu/mouse.c	24 Mar 2006 18:16:55 -0000	1.4
    +++ mcu/mouse.c	25 Mar 2006 14:28:46 -0000
    @@ -28,6 +28,7 @@
     #ifdef MCU

     #include <avr/io.h>
    +#include <util/delay.h>
     #include "ct-Bot.h"
     #include "mouse.h"

    @@ -45,18 +46,19 @@
      * Ã?bertrÃ¤gt ein Byte an den Sensor
      * @param data das Byte
      */
    -void maus_sens_writeByte(int8 data){
    +void maus_sens_writeByte(uint8 data){
     	int8 i;
     	MAUS_DDR  |= MAUS_SDA_PIN; 		// SDA auf Output

    -	for (i=7; i>=0; i--){
    +	for (i=8; i>0; i--) {
     		MAUS_PORT &= ~MAUS_SCK_PIN;		// SCK auf Low, vorbereiten
    -
     		//Daten rausschreiben
     		MAUS_PORT = (MAUS_PORT & (~MAUS_SDA_PINR)) |  ((data >> (7 - MAUS_SDA_NR)) & MAUS_SDA_PIN);
     		data = data <<1;		// nÃ¤chstes Bit vorbereiten

     		MAUS_PORT |= MAUS_SCK_PIN;		// SCK =1 Sensor uebernimmt auf steigender Flanke
    +
    +		asm("nop");
     	}
     }

    @@ -65,17 +67,19 @@
      * @return das Byte
      */
     int8 maus_sens_readByte(void){
    -	int i;
    -	char data=0;
    +	int8 i;
    +	int8 data=0;

     	MAUS_DDR  &= ~MAUS_SDA_PIN; 	// SDA auf Input

    -	for (i=7; i>-1; i--){
    +	for (i=8; i>0; i--) {
     		MAUS_PORT &= ~MAUS_SCK_PIN;		// SCK =0 Sensor bereitet Daten auf fallender Flanke vor !
     		data=data<<1;					// Platz schaffen
    +		asm("nop");
     		MAUS_PORT |= MAUS_SCK_PIN;		// SCK =1 Daten lesen  auf steigender Flanke

     		data |= (MAUS_SDA_PINR >> MAUS_SDA_NR) & 0x01;			//Daten lesen
    +		asm("nop");
     	}
     	return data;
     }
    @@ -85,11 +89,12 @@
      * @param adr Adresse
      * @param data Datum
      */
    -void maus_sens_write(int8 adr, uint8 data){
    -	int i;
    +void maus_sens_write(uint8 adr, uint8 data) {
     	maus_sens_writeByte(adr);
     	maus_sens_writeByte(data);
    -	for (i=0; i<75; i++){asm("nop");}	// mindestens 100 Mikrosekunden Pause!!!
    +
    +	// 56,7 us warten
    +	_delay_loop_2(227);
     }

     /*!
    @@ -99,9 +104,10 @@
      * @return das Datum
      */
     int8 maus_sens_read(uint8 adr){
    -	int i;
     	maus_sens_writeByte(adr);
    -	for (i=0; i<75; i++){asm("nop");}	// mindestens 100 Mikrosekunden Pause!!!
    +
    +	// 56,7 us warten
    +	_delay_loop_2(227);
     	return maus_sens_readByte();
     }

- Antworten:
  - Re: [ct-bot] CVS-Update
    - From: Benjamin Benz

- Referenzen:
  - [ct-bot] CVS-Update
    - From: Benjamin Benz
  - Re: [ct-bot] CVS-Update
    - From: Markus Hennecke
  - Re: [ct-bot] CVS-Update
    - From: Benjamin Benz
  - Re: [ct-bot] CVS-Update
    - From: Benjamin Benz

- Voriger (Datum): Re: [ct-bot] signed vs. unsigned char, Fabian Recktenwald
- Nächster (Datum): Re: [ct-bot] rc5-codes für Fernbedienung VIVANCO UR89, Andreas Staudenmayer
- Voriger (Thread): Re: [ct-bot] CVS-Update, Benjamin Benz
- Nächster (Thread): Re: [ct-bot] CVS-Update, Benjamin Benz
- Indizes:
  - Datum
  - Thread