Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

USB low-full-high speed peripherals

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

I have a project that I am developing using the FX2 platform to read an I2C based encoders.  The system will host five different encoders which are read by the I2C bus and I would like to read their data buffer and place into a buffer to be read back by the computer when you do a bulk read.  This way each transaction on the USB bus yields the buffer contents of all five encoders.  I was trying to write the return of EZUSBReadI2C into EP2FIFOBUF but EP2FIFOBUF won't accept the data.

0 Likes
1 Solution
Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh,

I was able to get the firmware to work the way I would like it to.  Thank you for the help.  To correct the return value changing from the default value to 1 instead of incrementing the default value when the encoder is turned, I added a second programming of the initial values using a EZUSB_WriteI2C(encoder, 17, (WORD)Setup_Data); .  Not reala second time.  I am not sure why this works but it does.  To get the unit to load defaults without a Vendor Request I added if(!(ENCODER_RDY))initialize_encoder(); to TD_Poll().  Now when I plug the unit in the encoders read correctly and there is no need for a vendor request unless you want to reset the default values.  Thanks for all the help!

void initialize_encoder()

{

int i, ii, iii;

BYTE Status;

BYTE xdata Setup_Data[17];

WORD Read_Data;

ii = 0;

iii =1;

//Reset the FIFO

FIFORESET = 0x80;

SYNCDELAY;

FIFORESET = 0x02;

SYNCDELAY;

FIFORESET = 0x00;

SYNCDELAY;

//Fill Encoder_Data with Setup contents

for (i=0; i < ENCODER_N; i++){

counter = default_counter;

Setup_Data[0] = 0x00; //Register to Start

Setup_Data[1] = 0x0B; //General Config

Setup_Data[2] = 0x00; //Status

Setup_Data[3] = 0x00; //Counter Byte 4

Setup_Data[4] = 0x00; //Counter Byte 3

Setup_Data[5] = 0x00; //Counter Byte 2

Setup_Data[6] = 0x00; //Counter Byte 1

Setup_Data[7] = 0x00; //Max Byte 4

Setup_Data[8] = 0x00; //Max Byte 3

Setup_Data[9] = 0xFF; //Max Byte 2

Setup_Data[10] = 0xFF; //Max Byte 1

Setup_Data[11] = 0x00; //Min Byte 4

Setup_Data[12] = 0x00; //Min Byte 3

Setup_Data[13] = 0x00; //Min Byte 2

Setup_Data[14] = 0x00; //Min Byte 1

Setup_Data[15] = 0x00; //LED A

Setup_Data[16] = 0x00; //LED B

Setup_Data[5] = MSB(default_counter); //Counter Byte 2

Setup_Data[6] = LSB(default_counter); //Counter Byte 1

EZUSB_WriteI2C(encoder, 17, (WORD)Setup_Data);

EZUSB_WaitForEEPROMWrite(encoder);

EZUSB_WriteI2C(encoder, 17, (WORD)Setup_Data);

EZUSB_WaitForEEPROMWrite(encoder);

Status = Encoder_Status(encoder);

Read_Data = Encoder_Read_Word(encoder, DATA_COUNTER_BYTE2);

counter = default_counter;

if(Read_Data != counter){// && (ENCODER_RDY)){

Encoder_LED(encoder, DECREASE, 500);

}

EP2FIFOBUF[ii] = LSB(Read_Data);

EP2FIFOBUF[iii] = MSB(Read_Data);

ii = ii + 2;

iii = iii + 2;

Encoder_LED(encoder,INCREASE, 50);

}

for (i=10;i<16;i++){

EP2FIFOBUF=0xFF;

}

ENCODER_RDY = TRUE;

}

View solution in original post

0 Likes
15 Replies
YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello,

1. Can you please let me know how you are confirming that the EP2FIFOBUF is not being assigned the data?

2. if(!(EP1INCS & bmEPBUSY))

The busy status of EP1 is checked when there are no data transfers done through it. Can you please let me know the reason?

Instead, the Full status of EP2FIFO (EP2CS.3) should be monitored before coping data to EP2FIFOBUF.

if(!(EP2CS & 0x08))

3. The EP2 IN data should be read from the host at the rate it is being written. Else the Buffer will not be available to be written if it is not empty.

4.

EP2BCH=0x00;

SYNCDELAY;

EP2BCL=0x10;

SYNCDELAY;

16 bytes are committed to the USB. Please commit  the required 5 Bytes. EP2BCL=0x05;

5. You can try hard coding values to the EP2FIFOBUF in the loop and check the values written by doing an IN transfer on EP2 from the control center.

Thanks,

Yatheesh

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

1. Can you please let me know how you are confirming that the EP2FIFOBUF is not being assigned the data?

When I read the data back using the CYControl utility the data read back does is not what I would expect to see.  I also have been using the KEIL debugger and looking at the FP2FIFOBUF  when the program is stopped and stepped through and I do not see it changing in the memory values.  I have also hardcoded values like 0x00 to this buffer and I can see it change when I program it EP2FIFOBUF[0] = 0x00 or whatever value I like but the program does not transfer the value or the pointer location when I program EP2FIFOBUF[i+1] = ENCODER_DATA[1];.  Also when I hardcode the data it only shows correct every other data request.

I also changed the code I set you to use EP0 using a vendor request and I am able to return the values from my encoders.  The problem with this methodology is that the existing unit uses 16bytes return using a bulk transfer and we would like for the unit to drop in replace it so we will need to format the data accordingly in the firmware.

2. if(!(EP1INCS & bmEPBUSY))

The busy status of EP1 is checked when there are no data transfers done through it. Can you please let me know the reason?

Instead, the Full status of EP2FIFO (EP2CS.3) should be monitored before coping data to EP2FIFOBUF.

if(!(EP2CS & 0x80))

Firmware was copied an I have not finished changing it for this application.  I was trying to get the data into the EP2FIFOBUF and was having issues.

3. The EP2 IN data should be read from the host at the rate it is being written. Else the Buffer will not be available to be written if it is not empty.

Is there a way to fill the buffer once the host requests the data using the FIFOBUF?  I think this can be done using vendor calls or a control transfer but I am not sure that it can be done with the FIFOBUF.

4.

EP2BCH=0x00;

SYNCDELAY;

EP2BCL=0x10;

SYNCDELAY;

16 bytes are committed to the USB. Please commit  the required 5 Bytes. EP2BCL=0x05;

The reason for this is we currently have a board that is in production that this unit will replace.  To test the prototype we want to replace that unit with this one then we will customize it for the application.  So that the software will understand the data we will need to format it like the existing unit which uses an external ADC on the ports rather than the I2C bus.

 

5. You can try hard coding values to the EP2FIFOBUF in the loop and check the values written by doing an IN transfer on EP2 from the control center.

I tried this and it does work however I receive good value bad value on the return read by either the CYCONTROL app or our software.

0 Likes
Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hello Yatheesh!  I have been able to write to the EP2FIFOBUF but one time I get the correct data(2nd bulk data transfer) then I will get a bad data(1st and 3rd Transfer).  Is there a way to get the data to continually look like the 2nd bulk transfer.  The two bottom transfers were from the control endpoint 0 using a Vendor Request and it formats the data correctly but I really need to use a bulk transfer to match our unit we are replacing.

Bulk IN success.

Buffer Contents

0000  F7 04 E8 14 DD 00 7F 00 ED 00 BF 2B EF 7F A7 DF

Bulk IN Transfer

Bulk IN success.

Buffer Contents

0000  00 04 00 14 00 00 00 00 00 00 00 00 00 00 00 00

Bulk IN Transfer

Bulk IN success.

Buffer Contents

0000  F7 04 E8 14 DD 05 7F 00 ED 00 BF 2B EF 7F A7 DF

Bulk IN Transfer

Bulk IN success.

Buffer Contents

0000  00 04 00 14 00 08 00 00 00 00 00 00 00 00 00 00

0000  00 05 00 14 00 0F 00 00 00 00 00 00 00 00 00 00

YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello,

Can you please share you updated project.

In the previous file you shared :

1. I see that the variables are being reused.

for example: in the TD_poll after the switch statement, ENCODER_DATA is reused after using the same in Encoder_Read() and Encoder_Write() functions.

ENCODER_DATA[1] = Status & 0xFF;

EP2FIFOBUF[i+1] = ENCODER_DATA[1];

Please use a different local variable here to get the status and assign it to EP2FIFOBUF.

2. WORD xdata Status;

Please declare it as a BYTE for convenient usage.

3.

In the Encoder_Read() function please change the EZUSB_ReadI2C() function parameter call as below.

EZUSB_ReadI2C(addr, 1, EP0BUF);

4. Please replace if(!(EP1INCS & bmEPBUSY)) with if(!(EP2CS & 0x80)) so that the full status of he EP2FIFO Buffer is checked before assigning any values to it.

Thanks,

Yatheesh

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh!

I have been able to get my project to work, but I have an odd issue.  When I load the hex file in the RAM or use the Keil Debugger the hardware works great.  When I load the iic file into the eeprom it changes the return value from the initial value to 0.  Please find the attached file and the attached app which should read the data back using a bulk transfer.

0 Likes
YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello,

When the EEPROM is used, on bootup, the firmware in loaded onto the RAM first and then the firmware is executed.

Once the firmware is loaded on the RAM on bootup from EEPROM, please try disconnecting the EEPROM from the I2C lines and see if you are seeing the same behavior?

Regarding the firmware:

1. In the TD_poll please check the full status of the EP2CS register.

if(!(EP2CS & 0x08))

2.

Please me know when the PC0 will be pulled low and how long the pin will be pulled low?

if PC0 is low for a longer time, then there are chances that the operation is re-executed.

If PC0 is used as a trigger (negative edge) to read the data in the TD_poll, then please use a global variable and set it to true when PC0 is first read high and then low.

Then check for the global variable if it is set to true, before entering the main operation in TD_poll.

Once the main operation is done set the global variable to false.

if (!global_var)   // if  global variable = 0/false

{

while (!PC0) ;  // wait for PC0 to read high

while (PC0);   // wait for PC0 to read low

global_var = true;

}

if(!(EP2CS & 0x08)){   // check for full status of EP2

if (ENCODER_RDY){

if (global_var){

global_var = false;

.

.  // encoder operations

.

} } }

Thanks,

Yatheesh

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh!

I tried disconnecting the EEPROM from the I2C lines as you suggested and did not see any change.  I also measured the time PC0 is low and 600nS for one encoder, if there are more (current config is 5) it will stay low until the STATUS of an encoder returns via the I2C bus that there is a change in state which could be upto 3mS unless the program is not sampling data then PC0 can go low indefinitely.  I did change the EP2CS & 0x08 so that the flag is checked and that works well.  I tried your suggested code to allow for the long PC0 state to prevent re-executed operation but the firmware will not enumerate when I compile it into the build.  I attached the modified code and the code you asked me to add is commented out.

The firmware I have works like I would like for it to when you manually load the RAM from either KEIL's debugger or by using the RAM load in the CYControl.  Could it be a problem with how the iic file is being parsed or maybe the data/code location so that the data is in the correct location of the EEPROM?  What happens is when I use the RAM load or the debugger the counter will start at the default value in the counter varable and will increase or decrease based on the rotation of the encoder.  If I use the EEPROM it loads fine and will show the default value but when the encoder is turned it will jump to 1.  It is very weird that it works fine in debug or the RAM load but not from an EEPROM load. I do get the below monitor error.

MONITOR ERROR 22: NO CODE MEMORY AT ADDRESS 0045H

MONITOR ERROR 22: NO CODE MEMORY AT ADDRESS 0055H

when I use the monitor but it appears to work OK.  I placed the Code in 0x80 and XDATA in 0x1000.  Any help you could provide for so I can get it to boot from the EEPROM would be appreciated!

Thanks,

Chris

0 Likes
YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello Chris,

The snippet of the code which was shared will wait for a negative edge on the PC0 line, which is causing the issue for enumeration.

I understood the operation. The code snippet can be ignored.

Please try the attached firmware files on RAM and large EEPROM and let me know if you still face the same issue?

I have made few changes in the project properties.

Thanks,

Yatheesh

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh,

I took a video of the results of testing with the files you sent.  I started with the EEPROM load and you will see the return value read 1.  When I load the RAM the unit runs correctly.  What I believe is the issue has to do with the way it is loading the default values.  There is a Vendor Request 0xFE that allows the encoder to be reset to default settings in case of an issue.  I can use the EEPROM to load the firmware and then perform the Vendor Request 0xFE and the unit will operate properly.  Is there a way to automate this so that I don't have to send the Vendor Request prior to the Bulk Read?

0 Likes
YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello,

Please make the changes as below:

1. Remove the EZUSB_INITI2C() function from TD_init() and place it under the DR_SetConfiguration() function in HID.c.

BOOL DR_SetConfiguration( void )

{ // Called when a Set Configuration command is received

  Configuration = SETUPDAT[ 2 ];

  EZUSB_INITI2C();

  return( TRUE );        // Handled by user code

}

2. Remove initialize_encoder() function from the HIDFW.c

3. Declare a global variable encoder_init:

BOOL encoder_init = FALSE;

and add the below code in TD_poll() to initialize the encoder.

if (encoder_init == FALSE)

{

initialize_encoder();

encoder_init == TRUE;

}

Please let me know the results.

Thanks,

Yatheesh

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh,

I added the code you sent but continue to get the same results.  If I load with the Keil Debugger or use a RAM load from the Control Panel it runs like it should.  The encoders read back value will increment the default value.  If I load the firmware using the EEPROM the read back will jump to 1 and will increment.  I can do the Vendor Command 0xFE and set the default values after the EEPROM load and the unit will increment from the default values like it is supposed to do.  Not real sure why it does this but it is easy enough to do a vendor command prior to the initial bulk read though I would really like to plug the unit in and begin Bulk Reading the encoder.

Best Regards,

Chris

0 Likes
YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello Chris,

The vendor command implementation in the host application before the encoder data is read from the device will be a better option here.

As we can see the failure to initialize the encoder in the first attempt in the TD_poll, the cause may also be in the firmware frame work flow.

I have used a similar framework as bulkloop in the attached project as the bulkloop firmware also has the similar operation where the 7 segment display is initialized and operated  to indicate the number of packets pending in the firmware.

Please try the attached firmware on your side.

password for zip: cypress

Thanks,

Yatheesh

Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh,

I think I finally figured out how to get the encoders to read right.  I added another call to initialize_encoder() in the vendor call with a short delay and the firmware seems to work like I need it to where the encoder will begin with a default number and increase or decrease from there.  Without this extra call the unit will cause the encoders to read back 1 when they are turned for the first time when the firmware is loaded from the EEPROM.  The Keil debugger works with out this extra call.  Any idea why this method seems to work or if there is a better method.  As we previously discussed I am using a Vendor call instead of the unit automatically initializing.  I would prefer that it auto initialize but the vendor call is acceptable.  I also tried the firmware you sent but it would not enumerate.

Best Regards,

Chris

0 Likes
YatheeshD_36
Moderator
Moderator 750 replies posted 500 replies posted 250 solutions authored
Moderator

Hello Chris,

Please let me know if the firmware I provided did not enumerate only on EEPROM load or both RAM and EEPROM load?

If it did not enumerate only on EEPROM Load, please provide me the schematics your board.

Thanks,

Yatheesh

0 Likes
Chris_Hawthorne
Level 3
10 replies posted 10 sign-ins 5 replies posted
Level 3

Hi Yatheesh,

I was able to get the firmware to work the way I would like it to.  Thank you for the help.  To correct the return value changing from the default value to 1 instead of incrementing the default value when the encoder is turned, I added a second programming of the initial values using a EZUSB_WriteI2C(encoder, 17, (WORD)Setup_Data); .  Not reala second time.  I am not sure why this works but it does.  To get the unit to load defaults without a Vendor Request I added if(!(ENCODER_RDY))initialize_encoder(); to TD_Poll().  Now when I plug the unit in the encoders read correctly and there is no need for a vendor request unless you want to reset the default values.  Thanks for all the help!

void initialize_encoder()

{

int i, ii, iii;

BYTE Status;

BYTE xdata Setup_Data[17];

WORD Read_Data;

ii = 0;

iii =1;

//Reset the FIFO

FIFORESET = 0x80;

SYNCDELAY;

FIFORESET = 0x02;

SYNCDELAY;

FIFORESET = 0x00;

SYNCDELAY;

//Fill Encoder_Data with Setup contents

for (i=0; i < ENCODER_N; i++){

counter = default_counter;

Setup_Data[0] = 0x00; //Register to Start

Setup_Data[1] = 0x0B; //General Config

Setup_Data[2] = 0x00; //Status

Setup_Data[3] = 0x00; //Counter Byte 4

Setup_Data[4] = 0x00; //Counter Byte 3

Setup_Data[5] = 0x00; //Counter Byte 2

Setup_Data[6] = 0x00; //Counter Byte 1

Setup_Data[7] = 0x00; //Max Byte 4

Setup_Data[8] = 0x00; //Max Byte 3

Setup_Data[9] = 0xFF; //Max Byte 2

Setup_Data[10] = 0xFF; //Max Byte 1

Setup_Data[11] = 0x00; //Min Byte 4

Setup_Data[12] = 0x00; //Min Byte 3

Setup_Data[13] = 0x00; //Min Byte 2

Setup_Data[14] = 0x00; //Min Byte 1

Setup_Data[15] = 0x00; //LED A

Setup_Data[16] = 0x00; //LED B

Setup_Data[5] = MSB(default_counter); //Counter Byte 2

Setup_Data[6] = LSB(default_counter); //Counter Byte 1

EZUSB_WriteI2C(encoder, 17, (WORD)Setup_Data);

EZUSB_WaitForEEPROMWrite(encoder);

EZUSB_WriteI2C(encoder, 17, (WORD)Setup_Data);

EZUSB_WaitForEEPROMWrite(encoder);

Status = Encoder_Status(encoder);

Read_Data = Encoder_Read_Word(encoder, DATA_COUNTER_BYTE2);

counter = default_counter;

if(Read_Data != counter){// && (ENCODER_RDY)){

Encoder_LED(encoder, DECREASE, 500);

}

EP2FIFOBUF[ii] = LSB(Read_Data);

EP2FIFOBUF[iii] = MSB(Read_Data);

ii = ii + 2;

iii = iii + 2;

Encoder_LED(encoder,INCREASE, 50);

}

for (i=10;i<16;i++){

EP2FIFOBUF=0xFF;

}

ENCODER_RDY = TRUE;

}

0 Likes