Невозможно прочитать значение из Mc Device с помощью функции WinUsb_ReadPipe в VC++ 2013

Я застрял с проблемой, связанной с функцией winusbReadpipe. Я использую Pic18f4550 Mc(компилятор XC8) и VC ++ 2013 (MFC).

Я просто пытаюсь читать и писать на / с устройства / хоста. Пример программы, предоставленной Microchip, работает нормально, и я могу отправлять данные на все конечные точки 01, 02, 03 в устройстве с хоста.

Однако я не могу прочитать какие-либо отзывы от устройства к хосту. Я читаю и пишу данные в двух отдельных потоках. Моя идея состоит в том, чтобы просто прочитать отзыв о нажатой кнопке на Моей демонстрационной доске или хотя бы команду echo back. Кажется, он просто входит один раз в функцию чтения, а затем останавливается. Не уверен насчет этого.

Я пытался искать через Интернет и реализовал все предложения, приведенные на разных форумах, но до настоящего времени безуспешно. хуже всего то, что я пытаюсь опубликовать свой запрос на форуме Microchip, но не могу зарегистрироваться, он всегда говорит, что администратор утвердит мой идентификатор, но пока ничего не произошло.

Ниже мой код как со стороны устройства, так и со стороны хоста. Пожалуйста скажите мне, если что-то еще требуется от моей стороны.

Я жду вашей поддержки в этом.

Спасибо,

Рахул


Код VC++:


Читать код темы


UINT CUsbHighSpeedDlg::ReadThread()
   {
      while (true)
      {
        if (AttachedState == TRUE)  //Do not try to use the read/write handles unless the USB device is attached and ready
        {
            m_DebugVal7.SetWindowTextW(TEXT("INSIDE read //pipe"));

WinUsb_ReadPipe(MyWinUSBInterfaceHandle, 0x81, &INBuffer[0], 64, &BytesRead, NULL);

            if (INBuffer[0] = 0x81)
            {
                m_DebugVal5.SetWindowTextW(TEXT("button true"));
            }

            if ((INBuffer[0] = 0x81) && (INBuffer[1] = 0x00))
                {
                    PushbuttonPressed = TRUE;
                    m_DebugVal5.SetWindowTextW(TEXT("button true"));
                }

                if ((INBuffer[0] = 0x81) && (INBuffer[1] = 0x01))
                {
                    PushbuttonPressed = FALSE;
                    m_DebugVal6.SetWindowTextW(TEXT("button False"));
                }

                }
        }   return 0;
}

Заголовочные файлы, объявленные в VC++ для использования функции чтения / записи.


//WinUsb_Initialize() needs to be called before the application can begin sending/receiving data with the USB device.

[DllImport("Winusb.dll", CharSet = CharSet::Seeifdef, EntryPoint = "WinUsb_Initialize", CallingConvention = CallingConvention::Winapi)]
BOOL __stdcall WinUsb_Initialize(
    _In_  HANDLE                   DeviceHandle,
    _Out_ PWINUSB_INTERFACE_HANDLE InterfaceHandle
    );

//WinUsb_WritePipe() is the basic function used to write data to the USB device (sends data to OUT endpoints on the device)
[DllImport("winusb.dll", CharSet = CharSet::Seeifdef, EntryPoint = "WinUsb_WritePipe", CallingConvention = CallingConvention::Winapi)]
BOOL __stdcall WinUsb_WritePipe(
    _In_      WINUSB_INTERFACE_HANDLE InterfaceHandle,
    _In_      UCHAR                   PipeID,
    _In_      PUCHAR                  Buffer,
    _In_      ULONG                   BufferLength,
    _Out_opt_ PULONG                  LengthTransferred,
    _In_opt_  LPOVERLAPPED            Overlapped
    );


//WinUsb_ReadPipe() is the basic function used to read data from the USB device (polls for and obtains data from
//IN endpoints on the device)
[DllImport("winusb.dll", CharSet = CharSet::Seeifdef, EntryPoint = "WinUsb_ReadPipe", CallingConvention = CallingConvention::Winapi)]
BOOL __stdcall WinUsb_ReadPipe(
    _In_      WINUSB_INTERFACE_HANDLE InterfaceHandle,
    _In_      UCHAR                   PipeID,
    _Out_     PUCHAR                  Buffer,
    _In_      ULONG                   BufferLength,
    _Out_opt_ PULONG                  LengthTransferred,
    _In_opt_  LPOVERLAPPED            Overlapped
    );



//WinUsb_SetPipePolicy() can be used to configure the behavior of the WinUSB use of the specified endpoint
[DllImport("winusb.dll", CharSet = CharSet::Seeifdef, EntryPoint = "WinUsb_SetPipePolicy", CallingConvention = CallingConvention::Winapi)]
BOOL __stdcall WinUsb_SetPipePolicy(
    _In_ WINUSB_INTERFACE_HANDLE InterfaceHandle,
    _In_ UCHAR                   PipeID,
    _In_ ULONG                   PolicyType,
    _In_ ULONG                   ValueLength,
    _In_ PVOID                   Value
    );


//WinUsb_Free() is used to free up resources/close the handle that was returned when calling WinUsb_Initialize()
[DllImport("winusb.dll", CharSet = CharSet::Seeifdef, EntryPoint = "WinUsb_Free", CallingConvention = CallingConvention::Winapi)]
BOOL __stdcall WinUsb_Free(
    _In_  WINUSB_INTERFACE_HANDLE InterfaceHandle
    );

//WinUsb_FlushPipe() is used to discard any data that may be "cached in a pipe".
[DllImport("winusb.dll", CharSet = CharSet::Seeifdef, EntryPoint = "WinUsb_Free", CallingConvention = CallingConvention::Winapi)]
BOOL __stdcall WinUsb_FlushPipe(
    _In_  WINUSB_INTERFACE_HANDLE InterfaceHandle,
    _In_  UCHAR PipeID
    );

Код микроконтроллера


Раздел объявления переменных


#elif defined(__XC8) && defined(FIXED_ADDRESS_MEMORY)
    USB_VOLATILE uint8_t EP1OUTEvenBuffer[64] @ EP1_EVEN_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP1OUTOddBuffer[64]  @ EP1_ODD_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP2OUTEvenBuffer[64] @ EP2_EVEN_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP2OUTOddBuffer[64]  @ EP2_ODD_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP3OUTEvenBuffer[64] @ EP3_EVEN_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP3OUTOddBuffer[64]  @ EP3_ODD_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP1INEvenBuffer[64] @ EP1IN_EVEN_DATA_BUFFER_ADDRESS;
    USB_VOLATILE uint8_t EP1INOddBuffer[64]  @ EP1IN_ODD_DATA_BUFFER_ADDRESS;
#else

#define FIXED_ADDRESS_MEMORY

#define EP1_EVEN_DATA_BUFFER_ADDRESS    0x480
#define EP1_ODD_DATA_BUFFER_ADDRESS     0x4C0

#define EP2_EVEN_DATA_BUFFER_ADDRESS    0x500
#define EP2_ODD_DATA_BUFFER_ADDRESS     0x540

#define EP3_EVEN_DATA_BUFFER_ADDRESS    0x580
#define EP3_ODD_DATA_BUFFER_ADDRESS     0x5C0

#define EP1IN_EVEN_DATA_BUFFER_ADDRESS    0x600 //  NEW MEMORY ADDRESS DECLARED
#define EP1IN_ODD_DATA_BUFFER_ADDRESS     0x640//  NEW MEMORY ADDRESS DECLARED

#endif //FIXED_MEMORY_ADDRESS

дескриптор


/* Device Descriptor */
const USB_DEVICE_DESCRIPTOR device_dsc=
{
    0x12,                   // Size of this descriptor in bytes
    USB_DESCRIPTOR_DEVICE,  // DEVICE descriptor type
    0x0200,                 // USB Spec Release Number in BCD format        
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_EP0_BUFF_SIZE,      // Max packet size for EP0, see usb_config.h
    0x04D8,                 // Vendor ID: 0x04D8 is Microchip's Vendor ID
    0x0052,                 // Product ID: 0x0052
    0x0000,                 // Device release number in BCD format
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x00,                   // Device serial number string index
    0x01                    // Number of possible configurations
};

/* Configuration 1 Descriptor */
const uint8_t configDescriptor1[]={
    /* Configuration Descriptor */
    0x09,//sizeof(USB_CFG_DSC),    // Size of this descriptor in bytes
    USB_DESCRIPTOR_CONFIGURATION,                // CONFIGURATION descriptor type
    0x2E,0x00,            // Total length of data for this cfg
    1,                      // Number of interfaces in this cfg
    1,                      // Index value of this configuration
    0,                      // Configuration string index
    _DEFAULT | _SELF,               // Attributes, see usb_device.h
    50,                     // Max power consumption (2X mA)

    /* Interface Descriptor */
    0x09,//sizeof(USB_INTF_DSC),   // Size of this descriptor in bytes
    USB_DESCRIPTOR_INTERFACE,               // INTERFACE descriptor type
    0,                      // Interface Number
    0,                      // Alternate Setting Number
    4,                      // Number of endpoints in this intf
    0xFF,                   // Class code
    0xFF,                   // Subclass code
    0xFF,                   // Protocol code
    0,                      // Interface string index

    /* Endpoint Descriptor */
    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP01_OUT,                  //EndpointAddress
    _BULK,                       //Attributes
    64,0x00,                    //size
    1,                         //Interval

    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP02_OUT,                   //EndpointAddress
    _BULK,                       //Attributes
    64,0x00,                    //size
    1,                          //Interval

    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP03_OUT,                   //EndpointAddress
    _BULK,                       //Attributes
    64,0x00,                    //size
    1,                          //Interval

     0x07,                       /*sizeof(USB_EP_DSC)*/// New Endpoint for Sending Data To Host
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP01_IN,                   //EndpointAddress// VALUE MODIFED FOR SENDING DATA
    _BULK,                       //Attributes
    64,0x00,                    //size
    1                          //Interval

};

Инициализация USB для массовой передачи


void APP_DeviceVendorThroughputTestInitialize()
{
    EP1OUTEvenHandle = NULL;
    EP2OUTEvenHandle = NULL;
    EP3OUTEvenHandle = NULL;
    EP1INEvenHandle = NULL;

    EP1OUTOddHandle = NULL;
    EP2OUTOddHandle = NULL;
    EP3OUTOddHandle = NULL;
    EP1INOddHandle = NULL;

    //Now that we are configured, enable the endpoints for use in the demo
    //  and start the initial transfers
    USBEnableEndpoint(_EP01_OUT,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    USBEnableEndpoint(2,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    USBEnableEndpoint(4,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    USBEnableEndpoint(_EP01_IN,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    //Prepare the OUT endpoints to receive the first packets from the host.

    EP1OUTEvenHandle = USBTransferOnePacket(_EP01_OUT, OUT_FROM_HOST,(uint8_t*)&EP1OUTEvenBuffer,64);   //First 64-bytes of data sent to EP1 OUT will arrive in the even buffer.
    EP1OUTOddHandle = USBTransferOnePacket(_EP01_OUT, OUT_FROM_HOST,(uint8_t*)&EP1OUTOddBuffer,64); //Second 64-bytes of data sent to EP1 OUT will arrive in the odd buffer.
    EP1OUTEvenNeedsServicingNext = true;    //Used to keep track of which buffer will contain the next sequential data packet.

    EP2OUTEvenHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTEvenBuffer,64);
    EP2OUTOddHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTOddBuffer,64);
    EP2OUTEvenNeedsServicingNext = true;    //Used to keep track of which buffer will contain the next sequential data packet.

    EP3OUTEvenHandle = USBTransferOnePacket(4, OUT_FROM_HOST,(uint8_t*)&EP3OUTEvenBuffer,64);
    EP3OUTOddHandle = USBTransferOnePacket(4, OUT_FROM_HOST,(uint8_t*)&EP3OUTOddBuffer,64);
    EP3OUTEvenNeedsServicingNext = true;    //Used to keep track of which buffer will contain the next sequential data packet.

   EP1INEvenHandle = USBTransferOnePacket(_EP01_IN, IN_TO_HOST,(uint8_t*)&EP1INEvenBuffer,64);  //First 64-bytes of data RECIVE to EP3 IN will arrive in the even buffer.
 //  EP1INOddHandle = USBTransferOnePacket(_EP01_IN, IN_TO_HOST,(uint8_t*)&EP1INOddBuffer,64);  //Second 64-bytes of data RECIVE to EP3 IN will arrive in the odd buffer.
 //   EP1INEvenNeedsServicingNext = true;
}

Код для передачи данных, Примечание: _EP01_Out =0x01 & _EP01_IN =0x81


if(EP1OUTEvenNeedsServicingNext == true)    //Check which buffer (even/odd) the next set of data is going to arrive in
    {
        if(!USBHandleBusy(EP1OUTEvenHandle))    //Check if the endpoint has received any data from the host.
        {

        PORTDbits.RD1=1;
        PORTDbits.RD2=0;
        switch(EP1OUTEvenBuffer[0])                 //Data arrived, check what kind of command might be in the packet of data.
        {
            case 0x81:  //Get push button state command from PC application.
EP1INEvenBuffer[0] = 0x81;
EP1INEvenHandle = USBTransferOnePacket(_EP01_IN, IN_TO_HOST,(uint8_t*)&EP1INEvenBuffer,64);
                break;

case 0x82:  //Toggle LED(s) command from PC application.
                 LATDbits.LD3=0;
                 break;

                 case 0x80:  //Toggle LED(s) command from PC application.
                 LATDbits.LD3=1;
                  break;
EP1OUTEvenHandle = USBTransferOnePacket(_EP01_OUT, OUT_FROM_HOST,(uint8_t*)&EP1OUTEvenBuffer,64);
            EP1OUTEvenNeedsServicingNext = false;

        }
    }
else        //else EP1OUTOdd needs servicing next
    {
         if(!USBHandleBusy(EP1OUTOddHandle))        //Check if the endpoint has received any data from the host.
                {

        PORTDbits.RD1=0;
        PORTDbits.RD2=1;
        switch(EP1OUTOddBuffer[0]) //Data arrived, check what kind of command might be in the packet of data.
       {
case 0x81:
  EP1INEvenBuffer[0] = 0x81;
EP1INEvenHandle = USBTransferOnePacket(_EP01_IN, IN_TO_HOST,(uint8_t*)&EP1INEvenBuffer,64);
break;

case 0x82:  //Toggle LED(s) command from PC application.
                 LATDbits.LD3=0;
                 break;
  case 0x80:  //Toggle LED(s) command from PC application.
                 LATDbits.LD3=1;
                  break;

}
 EP1OUTOddHandle = USBTransferOnePacket(_EP01_OUT, OUT_FROM_HOST,(uint8_t*)&EP1OUTOddBuffer,64);
            EP1OUTEvenNeedsServicingNext = true;
         }
    }

Конец кода


1 ответ

Я решаю проблему неработающей функции чтения канала winusb.

выполнив много ударов и проб, я сделал следующие изменения и смог успешно прочитать обратную связь потенциометра и нажатой кнопки.

фиксированный адрес памяти


#define EP1_EVEN_DATA_BUFFER_ADDRESS    0x480
#define EP1_ODD_DATA_BUFFER_ADDRESS     0x4C0

#define EP2_EVEN_DATA_BUFFER_ADDRESS    0x500
#define EP2_ODD_DATA_BUFFER_ADDRESS     0x540

#define EP3_EVEN_DATA_BUFFER_ADDRESS    0x580
#define EP3_ODD_DATA_BUFFER_ADDRESS     0x5C0

#define EP1IN_EVEN_DATA_BUFFER_ADDRESS    0x600 //  NEW MEMORY ADDRESS DECLARED
#define EP1IN_ODD_DATA_BUFFER_ADDRESS     0x640//  NEW MEMORY ADDRESS DECLARED
#endif //FIXED_MEMORY_ADDRESS

установка адреса конечной точки также как 1


 //Now that we are configured, enable the endpoints for use in the demo
    //  and start the initial transfers
    USBEnableEndpoint(1,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    USBEnableEndpoint(2,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    USBEnableEndpoint(3,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
 //   USBEnableEndpoint(1,USB_OUT_ENABLED|USB_IN_ENABLED|USB_HANDSHAKE_ENABLED|USB_DISALLOW_SETUP);
    //Prepare the OUT endpoints to receive the first packets from the host.

    EP1OUTEvenHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTEvenBuffer,64);   //First 64-bytes of data sent to EP1 OUT will arrive in the even buffer.
    EP1OUTOddHandle = USBTransferOnePacket(1, OUT_FROM_HOST,(uint8_t*)&EP1OUTOddBuffer,64); //Second 64-bytes of data sent to EP1 OUT will arrive in the odd buffer.
    EP1OUTEvenNeedsServicingNext = true;    //Used to keep track of which buffer will contain the next sequential data packet.

    EP2OUTEvenHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTEvenBuffer,64);
    EP2OUTOddHandle = USBTransferOnePacket(2, OUT_FROM_HOST,(uint8_t*)&EP2OUTOddBuffer,64);
    EP2OUTEvenNeedsServicingNext = true;    //Used to keep track of which buffer will contain the next sequential data packet.

    EP3OUTEvenHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTEvenBuffer,64);
    EP3OUTOddHandle = USBTransferOnePacket(3, OUT_FROM_HOST,(uint8_t*)&EP3OUTOddBuffer,64);
    EP3OUTEvenNeedsServicingNext = true;    //Used to keep track of which buffer will contain the next sequential data packet.

   EP1INEvenHandle = USBTransferOnePacket(1, IN_TO_HOST,(uint8_t*)&EP1INEvenBuffer,64); //First 64-bytes of data RECIVE to EP3 IN will arrive in the even buffer.
   EP1INOddHandle = USBTransferOnePacket(1, IN_TO_HOST,(uint8_t*)&EP1INOddBuffer,64);   //Second 64-bytes of data RECIVE to EP3 IN will arrive in the odd buffer.
    EP1INEvenNeedsServicingNext = true;

USB DESCRIPTOR


/* Device Descriptor */
const USB_DEVICE_DESCRIPTOR device_dsc=
{
    0x12,                   // Size of this descriptor in bytes
    USB_DESCRIPTOR_DEVICE,  // DEVICE descriptor type
    0x0200,                 // USB Spec Release Number in BCD format        
    0x00,                   // Class Code
    0x00,                   // Subclass code
    0x00,                   // Protocol code
    USB_EP0_BUFF_SIZE,      // Max packet size for EP0, see usb_config.h
    0x04D8,                 // Vendor ID: 0x04D8 is Microchip's Vendor ID
    0x0052,                 // Product ID: 0x0052
    0x0000,                 // Device release number in BCD format
    0x01,                   // Manufacturer string index
    0x02,                   // Product string index
    0x00,                   // Device serial number string index
    0x01                    // Number of possible configurations
};

/* Configuration 1 Descriptor */
const uint8_t configDescriptor1[]={
    /* Configuration Descriptor */
    0x09,//sizeof(USB_CFG_DSC),    // Size of this descriptor in bytes
    USB_DESCRIPTOR_CONFIGURATION,                // CONFIGURATION descriptor type
    0x2E,0x00,            // Total length of data for this cfg
    1,                      // Number of interfaces in this cfg
    1,                      // Index value of this configuration
    0,                      // Configuration string index
    _DEFAULT | _SELF,               // Attributes, see usb_device.h
    50,                     // Max power consumption (2X mA)

    /* Interface Descriptor */
    0x09,//sizeof(USB_INTF_DSC),   // Size of this descriptor in bytes
    USB_DESCRIPTOR_INTERFACE,               // INTERFACE descriptor type
    0,                      // Interface Number
    0,                      // Alternate Setting Number
    4,                      // Number of endpoints in this intf
    0xFF,                   // Class code
    0xFF,                   // Subclass code
    0xFF,                   // Protocol code
    0,                      // Interface string index

    /* Endpoint Descriptor */
    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP01_OUT,                  //EndpointAddress
    _BULK,                       //Attributes
    64,0x00,                    //size
    1,                         //Interval

    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP02_OUT,                   //EndpointAddress
    _BULK,                       //Attributes
    64,0x00,                    //size
    1,                          //Interval

    0x07,                       /*sizeof(USB_EP_DSC)*/
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP03_OUT,                   //EndpointAddress
    _BULK,                       //Attributes
    64,0x00,                    //size
    1,                          //Interval

     0x07,                       /*sizeof(USB_EP_DSC)*/// New Endpoint for Sending Data To Host
    USB_DESCRIPTOR_ENDPOINT,    //Endpoint Descriptor
    _EP01_IN,                   //EndpointAddress// VALUE MODIFED FOR SENDING DATA
    _BULK,                       //Attributes
    64,0x00,                    //size
    0                          //Interval

};

ТАК ОСНОВНО ПРОБЛЕМА ПОЛУЧИЛА РЕШЕНИЕ, ПОТОМУ ЧТО Я ИСПОЛЬЗУЮ 1 В КАЧЕСТВЕ АДРЕСНОГО АДРЕСА ДЛЯ ОБОИХ ВХОДОВ И ВЫХОДОВ

ОДНАКО ЭТО ОЗНАЧАЕТ, ЧТО МОЯ КОММУНИКАЦИЯ ДВУСТОРОННЯЯ, И Я ХОЧУ, ЧТОБЫ ЭТО БЫЛО НАПРАВЛЕНО. ТАК, ЧТО Я МОГУ ДОБИТЬСЯ ВЫСШЕГО BADWIDTH.

Я ДОЛЖЕН УЗНАТЬ, КАК СВЯЗАТЬСЯ С ИСПОЛЬЗОВАНИЕМ 1 ВНЕ КОНЕЧНОЙ ТОЧКИ И 81 В АДРЕСЕ КОНЕЧНОЙ ТОЧКИ.

СЧАСТЛИВОЕ ПРОГРАММИРОВАНИЕ!!

Другие вопросы по тегам