STM32 USB Middleware: HID Output Report Transaction Error - embedded

I've been having problems configuring my STM32 device to function with receiving HID Interrupt OUT transactions, where PC is host device.
I use the standard STM32 CubeMX provided USB Middleware, with edits to allow 2 endpoints, one OUT and one IN. Along with a customized HID report descriptor:
__ALIGN_BEGIN static uint8_t HID_ReportDesc[HID_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x01, // Usage (0x01)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x40, // Report Count (64)
0x09, 0x02, // Usage (0x02)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x40, // Report Count (64)
0x09, 0x02, // Usage (0x02)
0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
};
With the use of the USBD HID provided input report transaction function USBD_HID_SendReport, I can then observe the behavior of my device.
On the PC side, using USBLyzer software, I can confirm that the device is recognized by Windows, and configured accordingly, reporting back the descriptors with no errors. I then use HIDAPI to open the device, and read the reported values. This implementation works as expected, giving me communication of data from my device to the host.
However, there is no provided HID Output Report function, leaving me to implement this myself:
uint8_t USBD_HID_ReceiveReport (USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len){
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;
if(pdev->dev_state == USBD_STATE_CONFIGURED){
if(hhid->state == HID_IDLE){
hhid->state = HID_BUSY;
USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR, report, len);
}
}
return USBD_OK;
}
This function makes use of the same structure as the provided USBD_HID_SendReport function, instead using the USBD_LL_PrepareReceive function to prepare the EPOUT address to receive transaction, and then handling transmission through PCD.
After device initialization, I use my implemented USBD_HID_ReceiveReport function in an endless loop, being called repeatedly. I use hid_write in HIDAPI to transfer data to the device once. On debug, the device iterates through the loop, and enters the PCD endpoint transmission on every call. hid_write seemingly doesn't cause an update to my buffer as expected on the device, and USBlyzer reports a 'transaction error' on the OUT report.
Does anyone know the error in my implementation?

Related

More than one EndPoint on USB using PIC16F1455/1459

I am using a PIC16F1455 to collect data and send to a computer.
I used existing code for simple testing, which uses one end point only. Szymons code is my base, which I have expanded a bit.
I would like to use 3 endpoints for my application.
I have tried to set up the system to have 2 endpoints, but my second endpoint is not working.
I can add that
I have my configuration descriptor as below
The host will ask for Report Descriptor 1, but not for the 2nd one
when trying to send something from Endpoint 2, I can only see that UEP2 is owned by the SIE (Serial Interface Engine)
When I try to alter code so UEP1 should use UEP2 hardware, then it does not work. I did this by changing addresses from 01 to 02 and 81 to 82. Doing this with just one will make it work one way only.
Below my code, which I had with 2 endpoints, which gave no error. Just UEP2 does not work. Missing up interface count and message size will give an error. The comments will tell what changes can be done
I guess that if but channels should be the same, then the same configurations for both end points should be fine, only the endpoint number and addresses need change. Am I right?
I also understand, that UEP0 is used by the system and cannot be used for custom messages.
I need some ideas what could be wrong - how to get a second end point to work. I am out of ideas and I find it hard to google much on this. It should ask for both reports when using 2 end points, right?
// Configuration descriptor
const ConfigStruct ConfigurationDescriptor =
{
{
// Configuration descriptor
0x09, // Size of this descriptor in bytes
0x02, // CONFIGURATION descriptor type
0x29, // Total length of data for this cfg LSB // was 29 // 49 for 2 end points
0x00, // Total length of data for this cfg MSB
1,//INTF, // Number of interfaces in this cfg
0x01, // Index value of this configuration
SCON, // Configuration string index
0xA0, // Attributes (USB powered, wake-up))
0x32, // Max power consumption (in 2 mA steps)
},
{
// Generic HID Interface descriptor
0x09, // Size of this descriptor in bytes
0x04, // INTERFACE descriptor type
IHID, // Interface Number //<- I assume that it stays 1 just using UEP2. Cannot start from 2
0x00, // Alternate Setting Number
0x02, // Number of endpoints in this interface
0x03, // Class code (HID)
0x00, // Subclass code
0x00, // Protocol code 0-none, 1-Keyboard, 2- Mouse
0x00, // Interface string index
// Generic Hid Class-Specific descriptor
0x09, // Size of this descriptor in bytes
0x21, // HID descriptor type
0x11, // HID Spec Release Number in BCD format (1.11) LSB
0x01, // HID Spec Release Number in BCD format (1.11) MSB
0x00, // Country Code (0x00 for Not supported)
0x01, // Number of class descriptors
0x22, // Report descriptor type
0x2F, // Report Size LSB (47 bytes)
0x00, // Report Size MSB
// Generic HID Endpoint 1 In
0x07, // Size of this descriptor in bytes
0x05, // ENDPOINT descriptor type
0x81, // Endpoint Address //<----- changing to 82 will not work
0x03, // Attributes (Interrupt)
HRBC, // Max Packet Size LSB
0x00, // Max Packet Size MSB
0x01, // Interval (1 millisecond)
// Generic HID Endpoint 1 Out
0x07, // Size of this descriptor in bytes
0x05, // ENDPOINT descriptor type
0x01, // Endpoint Address //<--------changing on 02 will not work
0x03, // Attributes (Interrupt)
HRBC, // Max Packet Size LSB
0x00, // Max Packet Size MSB
0x01, // Interval (1 millisecond)
I found the mistake to be in the reply of reports - or descriptors. It would only allow to reply for endpoint 0 (endpoint 1 in hw), meaning when the host would ask for next descriptor, it would not get answer.
if((SetupPacket.bmRequestType & 0x1F) != 0x01 || (SetupPacket.wIndex0 != 0x00)) return;
needs to be
if((SetupPacket.bmRequestType & 0x1F) != 0x01 || (SetupPacket.wIndex0 > (InterfaceCount - 1))) return;
Then it works
Next step is that in PC host side, every end point is a connection by itself

UDR register always reads 0xFF

I have an ATTiny that is supposed to receive commands over UART. I have a simple display of eight LEDs that should show the contents of the most recent byte received. I am using an interrupt to read data as it is received. No matter what data I send UDR always reads 0xFF in the interrupt. I know the interrupt is being triggered since the display changes from 0x00 to 0xFF, but it never displays the value I sent over the serial bus.
This is how I enable UART.
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
This is the code in the interrupt. I have tested display() and it functions correctly on its own thus implying message is always 0xFF.
ISR(USART_RXC_vect) {
uint8_t message = UDR;
display(message);
}
I am confident that my computer is sending the correct information, but I have only tested it with a pseudo-terminal to print out the sent bytes. I intend to snoop the hardware connection with an oscilloscope, but I don't believe that is the issue. Is there something that is causing UDR to always read as 0xFF?
Edit:
I have snooped the connection with an oscilloscope and have verified that the computer is sending the correct data, at the correct rate. However, the ATTiny is not operating at the correct baud rate. At 2400 baud pulses should be about 400 microseconds long, however the microcontroller is producing pulses over 3 milliseconds long. This explains why it would always read 0xFF, the computer would send nearly the entire byte when the controller thought it was receiving the start bit, when the controller tried to read the remaining data the lines would be undriven, resulting in it reading all ones. I still don't know why this is the case as I believe I am properly setting the baud rate on the controller.
Edit:
The issue has been resolved. By default the clock prescaler is set to 8, so the device was only operating at 1MHz, not 8MHz. Setting the clock prescaler to 1 solved the problem.
There can be several problems with uart communication. First check some things:
Is controller configured with the right clock?
Internal/External
Is F_CPU defined for <util/setbaud.h>?
Is BAUD defined for <util/setbaud.h>?
Are you using a controller like ATmega16 that has special register access?
If you are using an external clock (that should not be devided) is CKDIV8 disabled in FUSES or in special registers at some controllers?
Is:
Baudrate,
Paritybit,
Stopbit
setup corret on Transmitter and Receiver
Debug:
If you are using a PC for communication, create a loopback at the UART adapter and check with a terminal (TeraTerm, Putty, ...) if the messages you send are received correctly.
You also can enable the TX controller and check if loopback is working on your uC.
If it is possible try to write the received data to some leds to check if some date is received
Is GND betweend receiver and transmitter connected?
Are the voltage levels between transmitter and receiver the same?
Do transmitter and receiver have its own source? (Then do not connect VCC!)
Check if the clock on the controller is correct (switch on an led with _delay_ms() function every second)
Example Program
#define F_CPU 12000000UL
#define BAUD 9600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
ISR(USART_RXC_vect)
{
volatile unsigned char message = UDR;
// If it is possible try to write the received data to
// LEDs (if there are some at your board)
display(message);
}
int main()
{
// To allow changes to clock prescaler it is necessary to set the
// CCP register (Datasheet page 23)!
CCP = 0xD8;
// RESET the clock prescaler from /8 to /1 !!!!
// Or it is necessary to divide F_CPU through the CLK_PRESCALER
CLKPSR = 0x00;
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1<<U2X);
#else
UCSRA &= ~(1<<U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
// Not necessary! Mostly ATmega controller
// have 8 bit mode initialized at startup
//UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
// If you are using ATmega8/16 it is necessary to do some
// special things to write to the UBRRH and UCSRC register!
// See ATmega16 datasheet at page 162
// Do not forget to enable interrupts globally!
sei();
while(1);
}
Please explain what the display() function is doing...

WebBrowser control: Block a specific ActiveX control from loading

I am hosting the WebBrowser control (using ATL), and I'm looking for a way to block a specific ActiveX control (by CLSID) from loading.
I know ProcessUrlAction can block ActiveX controls, but that's for the entire URL, it doesn't appear to allow you to block a specific ActiveX control by CLSID.
I don't see any specific event interfaces that get notified in MSHTML or the WebBrowser control.
Right now the only solution I can think of is to hook CoCreateInstanceEx and try to block it there.
Any simpler ideas?
ProcessUrlAction can block individual controls as well, you need to check if dwAction=URLACTION_ACTIVEX_RUN, if so then pContext will have the CLSID of the control that is about to run. If it's the one you want to block then set pPolicy to URLPOLICY_DISALLOW and return S_FALSE:
static CLSID CLSID_BAD = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
STDMETHOD(ProcessUrlAction)(LPCWSTR pwszUrl, DWORD dwAction, BYTE *pPolicy, DWORD cbPolicy, BYTE *pContext, DWORD cbContext, DWORD dwFlags, DWORD dwReserved)
{
if(URLACTION_ACTIVEX_RUN == dwAction && CLSID_BAD == *(CLSID *)pContext)
{
*pPolicy = URLPOLICY_DISALLOW;
return S_FALSE;
}
return INET_E_DEFAULT_ACTION;
}

Erasing a flash on TIVA TM4C123 Microcontroller

I have been trying to understand the following code which is writing to micro controller flash. The Microcontroller is TIVA ARM Cortex M4. I have read the Internal Memory Chapter 8 of Tiva™ TM4C123GH6PM Microcontroller Data sheet. At high level I understand Flash Memory Address (FMA), Flash Memory Data (FMD), and Flash Memory Control (FMC) and Boot Configuration (BOOTCFG).
Below are definitions for some of the variable used in the function.
#define FLASH_FMA_R (*((volatile uint32_t *)0x400FD000))
#define FLASH_FMA_OFFSET_MAX 0x0003FFFF // Address Offset max
#define FLASH_FMD_R (*((volatile uint32_t *)0x400FD004))
#define FLASH_FMC_R (*((volatile uint32_t *)0x400FD008))
#define FLASH_FMC_WRKEY 0xA4420000 // FLASH write key (KEY bit of FLASH_BOOTCFG_R set)
#define FLASH_FMC_WRKEY2 0x71D50000 // FLASH write key (KEY bit of FLASH_BOOTCFG_R cleared)
#define FLASH_FMC_MERASE 0x00000004 // Mass Erase Flash Memory
#define FLASH_FMC_ERASE 0x00000002 // Erase a Page of Flash Memory
#define FLASH_FMC_WRITE 0x00000001 // Write a Word into Flash Memory
#define FLASH_FMC2_R (*((volatile uint32_t *)0x400FD020))
#define FLASH_FMC2_WRBUF 0x00000001 // Buffered Flash Memory Write
#define FLASH_FWBN_R (*((volatile uint32_t *)0x400FD100))
#define FLASH_BOOTCFG_R (*((volatile uint32_t *)0x400FE1D0))
#define FLASH_BOOTCFG_KEY 0x00000010 // KEY Select
This function is used to erase a section of the flash. The function is called from a start address to and end address. I have not fully comprehended how this code works.
//------------Flash_Erase------------
// Erase 1 KB block of flash.
// Input: addr 1-KB aligned flash memory address to erase
// Output: 'NOERROR' if successful, 'ERROR' if fail (defined in FlashProgram.h)
// Note: disables interrupts while erasing
int Flash_Erase(uint32_t addr){
uint32_t flashkey;
if(EraseAddrValid(addr)){
DisableInterrupts(); // may be optional step
// wait for hardware idle
while(FLASH_FMC_R&(FLASH_FMC_WRITE|FLASH_FMC_ERASE|FLASH_FMC_MERASE)){
// to do later: return ERROR if this takes too long
// remember to re-enable interrupts
};
FLASH_FMA_R = addr;
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY){ // by default, the key is 0xA442
flashkey = FLASH_FMC_WRKEY;
} else{ // otherwise, the key is 0x71D5
flashkey = FLASH_FMC_WRKEY2;
}
FLASH_FMC_R = (flashkey|FLASH_FMC_ERASE); // start erasing 1 KB block
while(FLASH_FMC_R&FLASH_FMC_ERASE){
// to do later: return ERROR if this takes too long
// remember to re-enable interrupts
}; // wait for completion (~3 to 4 usec)
EnableInterrupts();
return NOERROR;
}
return ERROR;
}
Questions: How does the function exit out of the two while loops? How are variables FLASH_FMC_WRITE, FLASH_FMC_ERASE, and FLASH_FMC_MERASE changed? Can '0' be written as part of the erase process?
FLASH_FMC_WRITE, FLASH_FMC_ERASE, and FLASH_FMC_MERASE are individual bits in the FLASH_FMC_R register value (a bitfield). Look in the part's reference manual (or maybe datasheet) at the description of the FLASH_FMC_R register and you will find the description of these bits and more.
The while loops repeatedly read the FLASH_FMC_R register value and exit when the specified bits are set. The flash memory controller sets these bits when it's appropriate (read the reference manual).
Erasing flash means setting all bits to 1 (all bytes to 0xFF). Writing flash means setting select bits to 0. You cannot change a bit from 0 to 1 with a write.
You need to erase to do that. This is just the way flash works.

UDP with UWP behaves different

I wrote an app which sends an UDP datagram. If I try it on a Computer with Windows 10 on, it works, the other device (a Commercial one) responds correctly. If I execute the same app on an Windows 10 IoT (Raspberry Pi2), the device does not respond. First tought was a Firewall Problem. Thus I had a look on traffic with WireShark. In both cases the datagrams send over the WLAN, are the same. In case of Windows 10 I see the response from the device, in case of IoT there is no response.
Here is the method I use to send the datagram:
private async void FindDevice()
{
DatagramSocket socket = new DatagramSocket();
socket.MessageReceived += Socket_MessageReceived;
IPAddress ipAddressOfSender;
// device must be in the same network
if (IPAddress.TryParse("192.168.0.1", out ipAddressOfSender))
{
byte[] broadcastIpAddress = ipAddressOfSender.GetAddressBytes();
// Assuming to work with a class C IP address, so broadcast address looks like a.b.c.255
broadcastIpAddress[3] = 255;
using (var stream = await socket.GetOutputStreamAsync(new HostName(new IPAddress(broadcastIpAddress).ToString()), SendingPort.ToString()))
{
using (var writer = new DataWriter(stream))
{
byte[] helloSmartPlugs = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0x44, 0x49, 0x4d, 0x41,
0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0xff, 0x5e };
writer.WriteBytes(helloSmartPlugs);
await writer.StoreAsync();
}
}
}
}
In some samples there is also bound the listener port. It doesn't matter, if I do that or not, it still works on Windows, but not IoT. Can that someone explain me? I assumed I Need the listener port.
What could be the reason, the device does not answer in case of IoT? Are there Settings I have to provide with the socket?