c't

c't-Projekte - Mailinglisten


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

Re: [ct-bot] CVS-Update

Absender: Benjamin Benz
Datum: Mo, 03.04.2006 20:57:52
In-reply-to: <44254617.3050200@xxxxxxxxxxxxxxxxxx>
References: <4422CD39.5090701@xxxxxxxx> <4422ED3F.7010706@xxxxxxxxxxxxxxxxxx> <200603232313.12896.bbe@xxxxxxxx> <4424246A.50605@xxxxxxxx> <44254617.3050200@xxxxxxxxxxxxxxxxxx>


Hat bereits jemand Erfahrungen mit diesem Patch gesammelt?

MfG Benjamin Benz

Markus Hennecke wrote:
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();
 }
------------------------------------------------------------------------

_______________________________________________
ct-bot-entwickler Mailingliste
ct-bot-entwickler@xxxxxxxxxxxxxxxxx
http://www.heise.de/bin/newsletter/listinfo/ct-bot-entwickler