MCF52259 CMX USB stack  Problem

cancel
Showing results for 
Search instead for 
Did you mean: 

MCF52259 CMX USB stack  Problem

893 Views
Contributor I

Hello everyone,

i want to realize the communication from the board(MCF52259) to the PC, using the CMX usb stack with the CDC class,my project is CMXUSB_LITE_MCF5225X_1.0 download from freescale website, but when i try to install mcf5222x.inf ,the error occurs " Invallid Parameter , Unable to open 'C:\WINDOWS\system32\odbcconf.tmp' No such file or directory", what should i do? where should i find the file odbcconf.tmp?

Has anyone sucessfully made the CDC class easily integrated into MCF52259 Demo projects?

 Looking forward to answer.

 

PS: the attached file is mcf5222x.inf ,because the *.inf don't  confirm the the requirement to submit, you can modify  suffix to *.inf.

Labels (1)
0 Kudos
12 Replies

36 Views
Contributor I

I whish I could help, but my stuff is not working either.

 

Attached I've zipped up my .inf file along with an rtf showing what goes wrong when I first install my attempt at a CDC Virtual COM port device. 

 

The symptoms I'm getting seem to be different from yours, but it still doesn't work.

 

Mudwog

 

 

0 Kudos

36 Views
Contributor I

My stuff is not going well now, and about you ?

Could you send the file-usbser.sys to me ?

I dont find the appropriate file for MCF52259.

Thanks

0 Kudos

36 Views
Specialist V

Hi

 

usbser.sys is a Windows driver that is always on a Windows PC.

The *.inf file that is discovered by Windows matching VID & PID on first enumeration specifies that this is to be used.

 

Regards

 

Mark

 

0 Kudos

36 Views
Contributor I

hi ,

i cant enter into the interrupt ,i want to know which cause the problem occurs.

Firstly,

      /* Set interrupt level */
    MCF_INTC0_ICR53 = ip;
      /* Enable USB interrupts in the interrupt controller */
    MCF_INTC0_IMRH &= ~MCF_INTC_IMRH_INT_MASK53;
    MCF_INTC0_IMRL &= ~MCF_INTC_IMRL_MASKALL;

secondly, i set the interruput enter address in Vector table,

    ECTOR_TABLE:
     _VECTOR_TABLE:
     INITSP:  .long ___SP_INIT                   /* Initial SP   */
     INITPC:  .long _asm_startmeup         /* Initial PC */
     .
     .
     vector75: .long   _usb_it_handler       /* USB */   53+64=117 =0x75  (  I dont know this the method of calculating the interrupt enter address in vector table,please tell me whether is it correct?  )
     .
     .
      .org 0x400

 

lastly,

    #define usb_it_handler  _usb_it_handler

  

    __declspec(interrupt:0)
   void usb_it_handler(void)
    {
     .....
    }

 

I write the above process in my project. When plug in the USB cable to PC, this interrupt( usb_it_handler ) is not produced, Why? which cause the problem occurs.

 

Thanks for reading the above decription ,waiting for your answer!!

 

0 Kudos

36 Views
Contributor I

Hello cathychang,

 

I have not had any problems getting my interrupt handler working.  In my system the interrupt vectors are all hard coded in the protected bootloader section, and all of them (except reset) point to a jump table at a fixed location in my exec.  (My boot loaders use vectors in RAM, but my exec is fixed in FLASH).

 

I have come ot the realization that most of the poeple who use this forum are not "copecetic" with assembly language, but I'm "old school" and I prefer assembly whenever I can get away with it.  I have been translating my attempt at Virtual COM Port from Assembly to C, but I have not yet gotten down to the USB_INIT subroutine.  So I'm posting it here in assembly.  I have not had any problem with the interrupt.  My problems all come after enumeration when I just don't know what else to do.

 

So Here's my USB_INIT in assembly, I hope this helps:


////////////////////////////////////////////////////////////////////////////////////////////////////
// INIT USB
//is called from power up reset.
////////////////////////////////////////////////////////////////////////////////////////////////////
                 .align 2
USB_INIT:
                 LEA.L   (EP0Rx).L,%A0            //EP zero Receive is the start of the BDT
CLEAR_BDT_LOOP:
                 CLR.L   (%A0)+
                 CMPA.L  #BTD_END,%A0
                 BLT.B   CLEAR_BDT_LOOP           //Clear the BDT

                 LEA.L   (USB_BUFFERS_START).L,%A0
CLEAR_USB_BUFFERS_LOOP:
                 CLR.L   (%A0)+
                 CMPA.L  #USB_BUFFERS_END,%A0
                 BLT.B   CLEAR_USB_BUFFERS_LOOP   //Clear the Buffers used by USB
//
//Setup the BDT for Endpoint 0. I think that EP0 will always be the same.
//
           //EP0 Rx even (0)
                 MOVE.L  #0x88004000,%D0          //0x00400088 converted to little endian is 0x88004000.  These are all hard coded constants so why waste code.
                 MOVE.L  %D0,(EP0Rx).L            //set the control long in End Point zero receive 0
                 MOVE.L  #SETUP_PACKET,%D0        //get the address of the buffer to be used to receive the Setup Packet.
                 .word   0x02C0                   //BYTEREV %D0  because the BDT is little Endian
                 MOVE.L  %D0,(EP0Rx_ADDR).L       //save the buffer address in the BDT.

           //EP0 Rx odd (1)
                 MOVE.L  #0xC8004000,%D0
                 MOVE.L  %D0,(EP0Rx1).L           //set the control long in End Point zero receive 0
                 MOVE.L  #EP0_OUT_Data,%D0        //get the address of the buffer to be used,
                 .word   0x02C0                   //BYTEREV %D0  because the BDT is little Endian
                 MOVE.L  %D0,(EP0Rx1_ADDR).L      //save the buffer address in the BDT.

           //EP0 Tx even (0)             
                 MOVE.L  #0x88004000,%D0
                 MOVE.L  %D0,(EP0Tx).L            //set the control long in End Point zero receive 0
                 MOVE.L  #EP0_TX_DATA_BUFFER,%D0  //get the address of the buffer to be used,
                 .word   0x02C0                   //BYTEREV %D0  because the BDT is little Endian
                 MOVE.L  %D0,(EP0Tx_ADDR).L       //save the buffer address in the BDT.     
 
           //EP0 Tx odd (1)
                 MOVE.L  #0xC8004000,%D0
                 MOVE.L  %D0,(EP0Tx1).L           //set the control long in End Point zero receive 0
                 MOVE.L  #EP0_TX_DATA_BUFFER,%D0  //get the address of the buffer to be used,
                 .word   0x02C0                   //BYTEREV %D0  because the BDT is little Endian
                 MOVE.L  %D0,(EP0Tx1_ADDR).L      //save the buffer address in the BDT.


           //Setup the address of the BDT in three separate bytes for the USB silicon.
                 MOVE.L  #EP0Rx,%D0
                 ASR.L   #8,%D0
                 MOVE.B  %D0,(BDT_PAGE_01).L
                 ASR.L   #8,%D0
                 MOVE.B  %D0,(BDT_PAGE_02).L
                 ASR.L   #8,%D0
                 MOVE.B  %D0,(BDT_PAGE_03).L
 
                 CLR.L   %D0
                 MOVE.W  %D0,(CCE).L              //In the beginning there was a bit (14) that allowed the BDT to be Bigendian.
                                                  //It has since been removed from the manual, and possibly the silicon.
                                                  //The response from Freescale support to my question about it was basically that
                                                  //all the existing "stacks" use little endian (and obviously software engineers are too
                                                  //stupid to write their own), so they took it out.
                                                  //The bit might still be there who knows?
                                                  //There is no mention anywhere in their manual that the BDT is all LITTLE ENDIAN.
                                                  //The description of CCE bit 14 that they removed was the only reference to it.
           //select the USB clock
                 MOVE.B  #1,%D0
                 MOVE.B  %D0,(USB_CTRL).L         //1 selects the external oscillator clock to run the USB silicon.

           //Enable Endpoint zero  
                 MOVE.B  #0x0D,%D0
                 MOVE.B  %D0,(ENDPT0).L

           //Disable all USB interrupts
                 CLR.L   %D0
                 MOVE.B  %D0,(INT_ENB).L          //disable all USB interrupts
                 MOVE.B  %D0,(OTG_INT_EN).L       //disable all OTG interrupts
                 MOVE.B  %D0,(ERR_ENB).L          //disable all USB error interrupts
                 MOVE.B  #0xFF,%D0
                 MOVE.B  %D0,INT_STAT             //reset any pending USB interrupts
                 MOVE.B  %D0,(OTG_INT_STAT).L     //clear any pending OTG interrupts
                 MOVE.B  %D0,(ERR_STAT).L         //clear any pending USB error interrupt                

         //Enable USB interrupts:                 //////////////////////////////////////
         //ICR053 set the interrupt "level" and "Priority" for USB's interrupt
                 MOVE.B  #0x12,%D0                //Level 2, Priority 2, what ever that is. 
                 MOVE.B  %D0,(ICR053).L
         //Unmask Interrupts for USB source 53 on INTC0, this is vector 117 overall 64+53
                 MOVE.L  (IMRH0).L,%D0
                 ANDI.L  #0xFFDFFFFF,%D0          //the inverse of #0x00200000
                 MOVE.L  %D0,(IMRH0).L            //zero the bit for interrupt 53 on INTC0

                 MOVE.L  (IMRL0).L,%D0            //Zero the MASK ALL bit.
                 ANDI.L  #0xFFFFFFFE,%D0          //This only needs to be done once.
                 MOVE.L  %D0,(IMRL0).L            //clear the mask all bit

               //MOVE.B  #0x9B,%D0                //enable Stall, sleep, Token DNE,  error, USB reset interrupts but not enable attach, resume or sof_toK.
               //MOVE.B  #0xFF,%D0                //enable all interrupts
                 MOVE.B  #0xFB,%D0                //enable all interrupts except SOF
               //MOVE.B  #0xEB,%D0                //enable all interupts except sleep and SOF
                 MOVE.B  %D0,(INT_ENB).L
           //End of interrupt enabling.           //////////////////////////////////////

                 CLR.L   %D0
                 MOVE.B  %D0,(ADDR).L

           //enable the USB silicon
                 MOVE.B  #1,%D0
                 MOVE.B  %D0,(CTL).L

          //enable the USB DP pullup resistor.  This lets the PC know soemthing is plugged in.
                 MOVE.B  #0x84,%D0
                 MOVE.B  %D0,(OTG_CTRL).L
 
                 RTS

 

When I previewed this the forum messed up the code something awful, I can assure you my code si properly formatted and there are absolutely no TAB characters in it.  I guess I'll have to zip it up and attach it to make it readable:

 

  

 

 

0 Kudos

36 Views
Specialist I

> When I previewed this the forum messed up the code something awful,

 

Was that pasting the code straight in or posting it in via the "Insert Code" icon?

 

I've always found the latter to work OK. When composing the post it sometimes uses the wrong font in that box (proportional instead of monospace), but once posted it almost always looks OK.

 

Tom

 

0 Kudos

36 Views
Contributor I
////////////////////////////////////////////////////////////////////////////////////////////////////// USB ISR handling logic:////First INT_STAT the USB interrupt status register is examined to see what action to take//INT_STAT - Interrupt Status Register.; 0x001C0080//---------------------------------------------------//INT_STAT_USB_RESET     0x1 - call reset handler//INT_STAT_ERROR         0x2 - ignored//INT_STAT_SOF_TOK       0x4 - ignored//INT_STAT_TOK_DNE       0x8 - several actions are sorted out below.//INT_STAT_SLEEP        0x10 - a small sleep section that looks like it is not really needed//INT_STAT_RESUME       0x20 - a mirror of the sleep section, probably not needed//INT_STAT_ATTACH       0x40 - ignored//INT_STAT_STALL        0x80 - call the STALL handler////After checking reset, sleep, resume, and stall if the token done bit is not set//just exit.////second If INT_STAT indicates TOK_DNE (which might stand for "Token Done")//read the STAT register. STAT contains the endpoint number, the direction Rx or Tx//and an Odd/Even buffer bit.//STAT is used to figure out the endpoint number, which BDT entry is being used,//and if the transaction is Rx or Rx. ////After finding the status/control long in the BDT, get the PID. //There are five types of PIDs Token, Data, Handshake, Special, and Reserved.//The PID is only 4 bits.//For this application it is likely that only the Token Type PIDs are needed.//               PID//               ----//      Token: //         OUT   0001b 0x1//         IN    1001b 0x9//         SOF   0101b 0x5  - ignored//         SETUP 1101b 0xD  - call the setup handler for EP0, (if it's not EP0???)//      Data: //         DATA0 0011b 0x3//         DATA1 1011b 0xB//         DATA2 0111b 0x7//         MDATA 1111b 0xF//      Handshake: //         ACK   0010b 0x2//         NAK   1010b 0xA//         STALL 1110b 0xE//         NYET  0110b 0x6//      Special: //         PRE   1100b 0xC//         ERR   1100b 0xC - PRE and ERR are the same I'don't know anything about that.//         SPLIT 1000b 0x8//         PING  0100b 0x4//      Reserved://               0000b 0x0 - not used////From that information the decision of what handler to call for the Token is made://EP0 SETUP Handler (Rx) DONE?//EP0 OUT Handler (Rx)   DONE?//EP0 IN Handler  (Tx)   DONE//EP1 Control Tx???//EP2 Bulk Rx ???//EP2 Bulk Tx ???//// This should be simple!// But it is not simple for two reasons:// 1. there is no documentation// 2. windows is on the other end of the cable, a completely unpredictable unknown.////This handler written in c will be called by a real ISR written in assembly that handles//the context.////////////////////////////////////////////////////////////////////////////////////////////////////void USB_ISR_HANDLER()   {                        unsigned long BDT_control_long;    if (INT_STAT & 0x01)        //Check the USB reset bit in the USB interrupt status register.    {        USB_reset_handler();    }    if (INT_STAT & 0x02)        //Check the USB error BIT    {        USB_error_handler();    //(This never happens)    }    if (INT_STAT & 0x80)        //check the USB Stall bit    {        USB_stall_handler();    }    if (INT_STAT & 0x20)        //check the resume bit     {         USB_resume_handler();  //(This never happens)    }    if (INT_STAT & 0x10)        //Check the sleep bit    {         USB_sleep_handler();    }    if (INT_STAT & 0x08)        //If not one of the above, check for a token done. All setup and communication is done with tokens.    {        //////////////////////////////////////////////////////////////////        // Read the STAT register to find out what endpoint is being used.        //    STAT:        //    Bits 7,6,5,4 - the Endpoint number        //    Bit  3       - 1 for IN (Tx), 0 for OUT (Rx)        //    Bit  2       - 1 for ODD buffer, 0 for Even buffer        //    Bits 1,0     - reserved        //////////////////////////////////////////////////////////////////        if ((STAT & 0xF0) == 0)                     //check for EP0        {            if (STAT & 0x04)                        //check the odd buffer bit in STAT            {                BDT_control_long = EP0Rx1;          //use the ODD BDT control long            }            else            {                BDT_control_long = EP0Rx;           //use the even Buffer Descriptor Table control long for EP0.            }            //c_DISP_LONG(BDT_control_long);        //DEBUG            if ((STAT & 0x08) == 0x08)              //see if this was an IN or Tx token            {                EP0_in_handler();                   //This was an IN, call the Tx handler to send stuff to the Host.            }            else                                    //it must be an OUT or setup packet.            {                     BDT_control_long     &= 0x3C000000; //These 4 bits contain the PID.                if (BDT_control_long == 0x34000000) //check for a setup PID, PID is two bits to the right, a PID of 0x0D is the setup packet PID                {                    setup_packet_handler(); //  SETUP_PACKET_HANDLER();                }                else                {                    EP0_OUT_HANDLER();              //If it wasn't a setup it must be an OUT (Rx) of some sort.                }            }        }        else if ((STAT & 0xF8) == 0x18)  //check for EP1 IN (Tx)  (EP1 IN (Tx) control endpoint)         {            EP1_IN_HANDLER();            }        else if ((STAT & 0xF8) == 0x20)  //check for EP2 OUT (Rx)  (EP2 OUT (Rx)  bulk endpoint)         {            EP2_OUT_HANDLER();        }        else if ((STAT & 0xF8) == 0x28)  //check for EP2 IN (Tx)  (EP2 IN (Tx)  bulk endpoint)         {            EP2_IN_HANDLER();        }        else        {            c_DISP_CHAR("X");            //you'z foo-qued!        }    }    INT_STAT = 0xFF;   //write ones to clear all the bits in INT_STAT.}

 

I've been using a Verizon (Samsung) Hot Spot.  It is like paying some one $50 a month to kick you in the balls all day. 

Posting on a forum is unbelievably tedious, I didn't even know what those stupid looking things were, but I hovered my mouse over one and it said "insert code".  I have not used a TAB character in my code in my life, so here goes, I'll see if this works.

 

The c version of my USB ISR HANDLER  does exactly what the assembly version did.  I suspect that the ISR handler is the problem.

 

Here is my USB_ISR_HANDLER coded in C, (using the insert cide thingy between the offensive looking smileys:

 

Well that didn't go very well, three tries and I still couldn't get it to insert the code AFTER my introductory comments.

THis isn't going well for me.

 

Mudwog

 

 

 

 

 

 

 

 

 

0 Kudos

36 Views
Specialist I

I don't like the look of this:

 

 INT_STAT = 0xFF;   //write ones to clear all the bits in INT_STAT.

This may not be causing problems at the moment, but the above line points to some basic interrupt handling problems.

 

The best way to handle interrupts on all chips, is to recognise ONE interrupt, service it and then clear THAT ONE ONLY.

 

Freescale chips make this extremely easy with the "Write one to clear" system.

 

What your code is doing is to take a hardware interrupt, take some time to service some interrupts, and then it clears EVERY pending interrupt at the end of the function. The problem is it will clear any interrupts that have happened while you're in the service routine. That's a missed interrupt.

 

With this particular peripheral and with this particular use, things may only happen "one at a time" so what you're doing might work OK, but if you do the same thing with Serial or Ethernet chips you'll be in a whole mess of trouble. It is best to get this right in all your interrupt routines.

 

There are two basic ways to service ColdFire peripheral interrupts:

 

    uint8_t int_stat_copy = INT_STAT;

    if (int_stat_copy & 0x01)
    {
        USB_reset_handler();
    }
    And so on and so on...

    /* At the end of the routine, clear all that have been handled */
    INT_STAT = int_stat_copy;

Or, for some chips it is better to do it this way:

    int8_t int_stat_copy = INT_STAT;
    /* Now clear all that are about to be handled */
    INT_STAT = int_stat_copy;
    if (int_stat_copy & 0x01)
    {
        USB_reset_handler();
    }
    And so on and so on...

 

That version is "clean" as you're servicing a "snapshot" of pending interrupts at one time, but with the first one there's a delay between then and when you clear the requests to let the next ones in. This works OK on peripherals that can't interrupt all that often. With the second one you're clearing interrupts before servicing them, so with some chips that may "unlock" them to read more data over the top of the registers you are about to read. There's no "right way" - it is different for different peripherals.

 

At least it is more consistent than the MCF52259 UART. With that one you clear RXRDY in UISRn (and some error flags in USRn) by reading the FIFO except for OE which needs a command to UCRn, TXRDY by writing a byte or disabling TXRDY in the write-only UIMRn, DB with the RESET_BREAK_something command to UCRn and COS by reading UIPCRn.

 

The other way is:

 

    if (INT_STAT & 0x01)
    {
        USB_reset_handler(); /* Handle this interrupt, and then... */
        INT_STAT = 1; /* Clear this interrupt */
    }
    And so on and so on, but DON'T clear at the end...

 

You should read the manual very carefully because sometimes you might need to clear the interrupt request and then service it (by reading the other registers) and other times (most times) you service and then clear the request bit. With some simple peripherals (like UARTs) reading the received character clears the interrupt request and there's no separate "clear the request" needed.

 

Tom

 

 

 

0 Kudos

36 Views
Contributor I

Tom E,

 

Thanks for the advice.    Usually the SOF bit is set and one other bit.  The only case of multiple bits that I've seen is the combination of RESET and Sleep.  I'll definitely put in the bit clearing method that you described.

 

But, I'm still lost.

I can't find any information about  how to make the device work.

 

Once I saw a post from a fellow named Tsuneo Chinsei (on a different forum)  about some action that the device must do at the end of enumeration in order to get the usbser.sys driver going, but I've lost the link to that post.

 

As of now, at the end of enumeration Windows makes a sound "DONK, DONK, DONK", three real quick donks and sends a sleep command.  After that it just never talks again. 

I'll keep poking a stick at it.

 

thanks,

Mudwog

 

 

 

 

 

0 Kudos

36 Views
Specialist I

Cathy and Mudwog:

 

I don't know if you're pursuing this as a hobby or if it is part of a real paying job. It it is a paying job, then saving just a few days would pay for a complete running system with all of the USB stuff fixed and a complete running operating system as well.

 

I know nothing about uTasker apart from noticing Mark post here a lot and browsing his web pages.

 

Mudwog:

Check your private messages (that yellow envelope ICON).

 

Tom

 

0 Kudos

36 Views
Specialist V

Cathychang

 

Is the USB controller configured and its own interrupt enabled (the RESET interrupt is the first one to verify)? The USB interrupt looks to be configured correctly in the Coldfire interrupt controller.

 

Also check that the D+ pull-up has been configured so that the PC will attempt to start enumeration:

 

CTL = USB_EN_SOF_EN;

OTG_CTRL = (DP_HIGH | OTG_EN);

 

Of course, also verify that the USB clock s have been enabled and correctly configured.

 

Regards

 

Mark

 

 

0 Kudos

36 Views
Contributor I

hi Mudwog,

i have a look that attached file ,and then found that our problem is similar.

i think that the code is not correct maybe cause this porblem, how do you think about?

 

I hope that someone can give us the correctly *.inf file in MCF52259.

I will continue to search for the cause of the problem.

PS:the attached file is my code.

0 Kudos