View previous topic :: View next topic |
Author |
Message |
P51D
Joined: 25 Jan 2010 Posts: 36
|
FT245 speed problems -> assembler?! |
Posted: Tue Jun 01, 2010 2:05 pm |
|
|
hello all
I've some speed problems with the ft245 from ftdi because, i need to read all 128Byte of the RX-buffer faster than 800us.
in this moment, the datas are read with a c function:
Code: |
#define TXE PIN_D9 // Transmitt-enabmle pin
#define WR PIN_D11 // Write pin (high peak)
#define RX PIN_D8 // Receive data Pin
#define RD PIN_D10 // Read pin (during read low)
#define PWREN PIN_F6 // configurations-status
#define USART_DDR_out set_tris_d(0x0000 | (1<<9) | (1<<8)),set_tris_f(0x0007 | (1 << 6))
#define USART_DDR_in set_tris_d(0x00F8 | (1<<9) | (1<<8)),set_tris_f(0x003F | (1 << 6))
#define D0 PIN_F3 // Data-Pins
#define D1 PIN_F4
#define D2 PIN_F5
#define D3 PIN_D3
#define D4 PIN_D4
#define D5 PIN_D5
#define D6 PIN_D6
#define D7 PIN_D7
#define rxBuf_max 50 // buffer size
static volatile int8 index_rxBuf_R = 0; // Index of last write RX-Buffer
static volatile int8 index_rxBuf_W = 0; // Index of last read RX-Buffer
static volatile int8 rxBuf[rxBuf_max + 1]; // RX-Buffer
void usart_rx(void){ // read function (polling)
int8 data = 0; // data
if(input_state(RX) == 0){ // if new data in the FTDI buffer
if(index_rxBuf_W == rxBuf_max){ // ringbuffer
index_rxBuf_W = 0;
}
else{
index_rxBuf_W ++;
}
// take datas and set it dynamic in the buffer
output_low(RD); // read data
if(input_state(D0) == 1) data |= (1 << 0);
if(input_state(D1) == 1) data |= (1 << 1);
if(input_state(D2) == 1) data |= (1 << 2);
if(input_state(D3) == 1) data |= (1 << 3);
if(input_state(D4) == 1) data |= (1 << 4);
if(input_state(D5) == 1) data |= (1 << 5);
if(input_state(D6) == 1) data |= (1 << 6);
if(input_state(D7) == 1) data |= (1 << 7);
rxBuf[index_rxBuf_W] = data; // store data
output_high(RD); // read finished
}
}
|
then I woud call the function like this:
Code: |
int i = 0;
for(i = 0; i < 128; i ++){
usart_rx();
}
|
what effect to the speed has it, when I try to write the function usart_rx() and her call in assembler?
I wrote "try" because I have no mutch expirience with assembler.
Hope you can help me.
best wishes
P51D |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Tue Jun 01, 2010 2:28 pm |
|
|
The key to higher speed is a reasonable assignment of data pins, allowing to read the data at least in nibbles. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Jun 01, 2010 3:04 pm |
|
|
List your:
- processor
- clock frequency
- compiler version
With a PIC18 and standard_io at 20MHz your code takes 602us.
With fast_io it is reduced to 577us.
Why are you reading all bits separately? It seems like your hardware is lined out to make it possible to read all 8 bits with a single input command.
Replace Code: | if(input_state(D0) == 1) data |= (1 << 0);
if(input_state(D1) == 1) data |= (1 << 1);
if(input_state(D2) == 1) data |= (1 << 2);
if(input_state(D3) == 1) data |= (1 << 3);
if(input_state(D4) == 1) data |= (1 << 4);
if(input_state(D5) == 1) data |= (1 << 5);
if(input_state(D6) == 1) data |= (1 << 6);
if(input_state(D7) == 1) data |= (1 << 7);
rxBuf[index_rxBuf_W] = data; // store data | by Code: | rxBuf[index_rxBuf_W] = input_d(); // store data
| 423us with standard_io.
372us using fast_io
Thanks again for the Stopwatch function in the MPLAB Simulator. |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Wed Jun 02, 2010 2:44 am |
|
|
Processor: ds30F6012A
Clock: 16MHz with fuse HS2_PLL16
Compiler: 4.107 ?(I think, because I'm now not at the right pc) with the PCWHD IDE
I used the fast-io version
And I'm reading the bits separtly, becaus in this hardware-version they are lined, but I don't know how it is in the next version.
The next problem is, that this is a 16 bit port and the other pins of these port are used to controll the ft245. how could I read and write only the lower byte?
and the oder problem is:
Quote: |
128Byte of the RX-buffer faster than 800us
|
did you realy read all 128 bytes in 500us?
thank a lot for the answers
best regards
P51D |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jun 02, 2010 4:55 am |
|
|
Quote: | And I'm reading the bits separtly, becaus in this hardware-version they are lined, but I don't know how it is in the next version. | Tell your hardware engineer it is important to you to have them in the right sequence and starting at port pin 0. If you don't discuss this it will be a gamble what he's up to, though it is easy for him to arrange the lines as you want them.
Quote: | did you realy read all 128 bytes in 500us? | On a PIC18 at 20MHz, yes. I don't have the PCWHD compiler so can't test for the DS30 at 16MHz. You can test this yourself using the free MPLAB IDE. Select the simulator as debugging device and use the stopwatch screen for measurements.
Quote: | how could I read and write only the lower byte? | Reading is easy, just throw away the unused part: Code: | data8 = input_d() & 0x00FF; // for the lower 8 bits
data8 = (input_d() >> 8) & 0x00FF; // for the higher 8 bits
or use the CCS function make8:
data8 = make8(input_d(), 0); // for the lower 8 bits
data8 = make8(input_d(), 1); // for the higher 8 bits |
Writing 8 bits to a 16 bit port means you'll first have to read the port, modify the data and then write back the result: Code: | int8 data8 = 123;
int16 data16 = input_d();
data16 &= 0xFF00; // clear lower 8 bits
data16 = data16 | data8; // Add the new 8 bit data
output_d(data16); |
|
|
|
SET
Joined: 15 Nov 2005 Posts: 161 Location: Glasgow, UK
|
|
Posted: Wed Jun 02, 2010 8:21 am |
|
|
In summary, you are reading a byte where the bits are split across two ports?
I would do something like:
Read 1st Port
Mask and shift
Read 2nd Port
Mask and shift
'or' them together
If need be you could then use the byte as an index into a look up table. Not be hugely faster but should save a few instructions? |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Wed Jun 02, 2010 9:00 am |
|
|
SET wrote: | In summary, you are reading a byte where the bits are split across two ports?
|
No, but the port is a 16 bit port with controll-pin.
I've tested it with the new read-function:
~200us but there where no data availlable in the rx-buffer from the ftdi.
there is also an other problem:
I can't do this with a for-loop because I need a main-programm-loop speed about <= 10 us.
reading with more steps would be the best way, or are there other possibilitys?
best wishes
P51D |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Thu Jun 03, 2010 6:21 am |
|
|
hello all
I've tested the new version with 126 bytes to rx.
Code: |
void usart_rx(void){ // read function (polling)
if(input_state(RX) == 0){ // if new data in the FTDI buffer
if(index_rxBuf_W == rxBuf_max){ // ringbuffer
index_rxBuf_W = 0;
}
else{
index_rxBuf_W ++;
}
// take datas and set it dynamic in the buffer
output_low(RD); // read data
rxBuf[index_rxBuf_W] = ((input_d() & 0xF8) | ((input_f() & 0x38) >> 3)); // store data
output_high(RD); // read finished
}
}
|
There are 2 ports for the FT245 because the others are used also to fast communications.
the receiving case of the Parameters looks like this:
Code: |
switch(PAR_state){ // Werte in Ausgabe-Arrays speichern
case waitRED:
red_buf[k] = rxBuf[index_rxBuf_R];
PAR_state = waitGREEN;
break;
case waitGREEN:
green_buf[k] = rxBuf[index_rxBuf_R];
PAR_state = waitBLUE;
break;
case waitBLUE:
blue_buf[k] = rxBuf[index_rxBuf_R];
PAR_state = waitAX1;
break;
case waitAX1:
x_achse_buf[k] = (rxBuf[index_rxBuf_R] << 4);
PAR_state = waitAX2;
break;
case waitAX2:
x_achse_buf[k] |= (rxBuf[index_rxBuf_R] >> 4);
y_achse_buf[k] = ((rxBuf[index_rxBuf_R] & 0x0F) << 8);
PAR_state = waitAX3;
break;
case waitAX3:
y_achse_buf[k] |= rxBuf[index_rxBuf_R];
if(k == (Stream_buf_max - 1)) // Ringbuffer Steuerung
k = 0;
else
k ++;
PAR_state = waitRED;
if(index_par == NUM){
RS232_state = waitACK;
txBuf_Write(ACK);
index_par = 0;
output_low(led_red);
}
|
The LED is high for ~660us but after 700 us the datas were used. Is there a possibility to redefine the code for faster reading?
the hole sending and receiving protokoll looks like this:
Code: |
void RS232(void){
static unsigned int8 RS232_state = 0; // Protokollstatus
static unsigned int16 index_par = 0; // Array-Variable für Parameters
static unsigned int16 NUM = 0; // Anzahl zu übertragenden Werte
static unsigned int1 num_teil = 0; // 16Bit Anzahl zusammensetzen
static unsigned int16 k = 0; // Speichervariable für Steuerung
static unsigned int8 PAR_state = 0;
static unsigned int8 temp_cmd = 0;
usart_tx(); // Wenn Daten im TX-Buffer, senden
usart_rx(); // Wenn Daten im FTDI-Buffer, entgegennehmen
if(index_rxBuf_W == index_rxBuf_R){ // Buffer Error abgleichen
return; // Wenn keine neuen Daten => aus Funktion heraus springen
}
if(index_rxBuf_R == rxBuf_max){ // Erhöhen
index_rxBuf_R = 0;
}
else{
index_rxBuf_R ++;
}
switch (RS232_state){
case waitENQ:
switch (rxBuf[index_rxBuf_R]){
case '?': // Suche der LCU
printf(txBuf_Write,"USB LCU");
output_high(LED_green);
break;
case ENQ:
RS232_state = waitSOH; // In nächsten State wechselnd
txBuf_Write(ACK);
break;
default:
txBuf_Write(rxBuf[index_rxBuf_R]); // Unbekanter Befehl zurückgeben
break;
}
break;
case waitSOH: // Header der Übertragung
if (rxBuf[index_rxBuf_R] == SOH){
RS232_state = waitCMD;
}
else{
RS232_state = waitENQ;
txBuf_Write(NACK);
}
break;
case waitCMD: // Kommando
switch (rxBuf[index_rxBuf_R]){
case STREAM: // Werte streamen
RS232_state = waitNUM;
temp_cmd = rxBuf[index_rxBuf_R];
break;
case STOP: // Projektor aus
command = rxBuf[index_rxBuf_R];
txBuf_Write(ACK);
RS232_state = waitACK;
break;
case 0x01: // Show 1
command = rxBuf[index_rxBuf_R];
txBuf_write(ACK);
RS232_state = waitACK;
break;
default:
RS232_state = waitENQ;
txBuf_Write(NACK);
command = 0;
break;
}
break;
case waitNUM: // Anzahl zu empfangender Werte in 16 Bit
if(num_teil == 0){ // 2 8Bit Werte zu 16 Bit Wert zusammensetzen
NUM = (rxBuf[index_rxBuf_R] << 8);
num_teil = 1;
}
else{
NUM |= rxBuf[index_rxBuf_R];
RS232_state = waitPAR;
num_teil = 0;
}
break;
case waitPAR:
index_par ++;
output_high(LED_red);
switch(PAR_state){ // Werte in Ausgabe-Arrays speichern
case waitRED:
red_buf[k] = rxBuf[index_rxBuf_R];
PAR_state = waitGREEN;
break;
case waitGREEN:
green_buf[k] = rxBuf[index_rxBuf_R];
PAR_state = waitBLUE;
break;
case waitBLUE:
blue_buf[k] = rxBuf[index_rxBuf_R];
PAR_state = waitAX1;
break;
case waitAX1:
x_achse_buf[k] = (rxBuf[index_rxBuf_R] << 4);
PAR_state = waitAX2;
break;
case waitAX2:
x_achse_buf[k] |= (rxBuf[index_rxBuf_R] >> 4);
y_achse_buf[k] = ((rxBuf[index_rxBuf_R] & 0x0F) << 8);
PAR_state = waitAX3;
break;
case waitAX3:
y_achse_buf[k] |= rxBuf[index_rxBuf_R];
if(k == (Stream_buf_max - 1)) // Ringbuffer Steuerung
k = 0;
else
k ++;
PAR_state = waitRED;
if(index_par == NUM){
RS232_state = waitACK;
txBuf_Write(ACK);
index_par = 0;
output_low(led_red);
}
break;
}
break;
case waitACK:
if(rxBuf[index_rxBuf_R] == ACK){ // ACK empfangen,
RS232_state = waitEOT;
}
break;
case waitEOT: // Übertragung beendet
if(rxBuf[index_rxBuf_R] == EOT){
RS232_state = waitENQ;
if(temp_cmd == STREAM){
command = temp_cmd;
temp_cmd = 0;
}
}
break;
}
}
|
Thank for helping
best wishes
P51D |
|
|
|