I just began to understand the embedded world (after Arduino, RPi, etc) with the STM32F103 and FreeRTOS + Libopencm3. My first challenge is to interface a DS18B20, temperature sensor with my microprocessor. The 1-Wire bus is quite easy to understand but not native supported so I followed your advised and go for 1-wire over UART with DMA.
DS18B20 has DATA on USART2TX (+4k7 pullup + diode) and USART2RX, VCC to 5V and GND.
Initialization of 1-Wire :
static void ow_init(void)
{
// One-Wire
// Already done : rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);
usart_set_baudrate(USART2, 115200);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_mode(USART2, USART_MODE_TX);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_enable(USART2);
rcc_periph_clock_enable(RCC_DMA1);
}
1-Wire Reset :
uint8_t ow_reset(void)
{
usart_disable_rx_dma(USART2);
usart_disable_tx_dma(USART2);
usart_set_baudrate(USART2, 9600);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_mode(USART2, USART_MODE_TX);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
usart_send(USART2, 0xf0);
while(usart_get_flag(USART2, USART_SR_TC));
uint8_t ow_presence;
ow_presence = usart_recv(USART2);
usart_set_baudrate(USART2, 115200);
usart_set_databits(USART2, 8);
usart_set_stopbits(USART2, USART_STOPBITS_1);
usart_set_mode(USART2, USART_MODE_TX_RX);
usart_set_parity(USART2, USART_PARITY_NONE);
usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
if(ow_presence != 0xf0)
{
return 1;
}
return 0;
}
Getting the scratchpad with :
void ow_convert_to_scratchpad(void)
{
const uint8_t convert_T[] = {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, // 0xCC
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00}; // 0x44
dma_channel_reset(DMA1, DMA_CHANNEL7);
dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&USART2_DR);
dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) convert_T);
dma_set_number_of_data(DMA1, DMA_CHANNEL7, sizeof(convert_T));
dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);
dma_enable_channel(DMA1, DMA_CHANNEL7);
usart_enable_tx_dma(USART2);
}
uint16_t ow_get_scratchpad(void)
{
const uint8_t read_scratch[] = {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, // 0xCC
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, // 0xBE
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t buf[8];
dma_channel_reset(DMA1, DMA_CHANNEL6);
dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t)&USART2_DR);
dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) buf);
dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
dma_set_number_of_data(DMA1, DMA_CHANNEL6, sizeof(read_scratch));
dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6);
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6);
dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_LOW);
dma_channel_reset(DMA1, DMA_CHANNEL7);
dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&USART2_DR);
dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) read_scratch);
dma_set_number_of_data(DMA1, DMA_CHANNEL7, sizeof(read_scratch));
dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);
dma_enable_channel(DMA1, DMA_CHANNEL6);
dma_enable_channel(DMA1, DMA_CHANNEL7);
usart_enable_tx_dma(USART2);
usart_enable_rx_dma(USART2);
while(dma_get_interrupt_flag(DMA1, DMA_CHANNEL6, DMA_TCIF));
uint16_t tt = 0;
for(int i=0;i<32; i++)
{
uart1_printf("Bit : %d \n\r", buf[i]);
if(buf[i] == 0xff)
{
tt = (tt >> 1) | 0x8000;
}
else
{
tt = tt >> 1;
}
}
return tt;
}
static void demo_task(void *args)
{
(void)args;
for (;;) {
uart1_printf("Hello\n\r");
uint8_t p = ow_reset();
uart1_printf("presence = %d\n\r", p);
ow_convert_to_scratchpad();
for(int i=0; i<5000000; i++)
{
__asm__("nop");
}
ow_reset();
uint16_t t = ow_get_scratchpad();
uart1_printf("t = %d \n\r", t);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
And finally the task that tries to reach the DS18B20
static void demo_task(void *args)
{
(void)args;
for (;;) {
ow_reset();
ow_convert_to_scratchpad();
vTaskDelay(pdMS_TO_TICKS(500));
ow_reset();
uint16_t t = ow_get_scratchpad();
uart1_printf("t = %d \n\r", t);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
I receive some bits as 0xCC, 0xBE, 0xFF but no more answer.
Ok, so
rcc_periph_clock_enable(RCC_USART2);
was missing so USART2 can't do its job. I can send and receive data now.
The reset function works except this line (it wait indefinitely) :
while(usart_get_flag(USART2, USART_SR_TC));
I don't understand why this flag is not true when the transmission is complete... But I have 0x00 on RX line so I think the sensor is responding (I hope...)
My function ow_convert_to_scratchpad with DMA looks like being blocking. I don"t know why...
I just tried (for fun...) to replace the whole DMA by hardcoding the sent of 0xCC, 0x44, 0xCC, 0xBE and the read but no answer (0x00) from the sensors.
I am kind of late to the party, but... Have you tried something a bit less convoluted first? (Simpler to check I mean)
Like asking a single DS18B20 its address?
Reset bus and check presence.
Send search ROM cmd (write byte 0xF0)
loop 64 times reading address bits from LSB to MSB {
read bit i
read bit i complement
check they are 1 and 0 or the other way around
send bit i back to device so it sends you back the next bit
}
At the end you have the 8 byte of the device address. 1 byte family 0x28 48 bit address 1 byte CRC8 to check the whole thing is correct.
Related
I need to communicate STM32L062 with MC3413 accelerometer, but communication only works when uC clock settings are default (16MHz HSI) and generated by CubeMX. Any change (for example changing source to ~4MHz MSI) causes slave to not give ACK. Im beginner and i've tried many combinations of prescalers etc. and i have no clue what is wrong. Here is my main loop code:
while (1) {
uint8_t config1;
config1 = 0xC0;
status[0]=HAL_I2C_Mem_Write(&hi2c1, 0x98, 0x07, 1, &config1, 1, 100); // 0xC0 konfiguruje akcelerometr w tryb standby
config1 = 0x78;
status[1]=HAL_I2C_Mem_Write(&hi2c1, 0x98, 0x08, 1, &config1, 1, 100); // 0x7A wlacza wykrywanie tapniec we wszystkich osiach i 256Hz sampling
config1 = 0x05;
status[2]=HAL_I2C_Mem_Write(&hi2c1, 0x98, 0x20, 1, &config1, 1, 100); // 0x05 powinno ustawic rozdzielczosc 14bit i zakres 2g
config1 = 0xC1;
status[3]=HAL_I2C_Mem_Write(&hi2c1, 0x98, 0x07, 1, &config1, 1, 100); // 0xC1 konfiguruje akcelerometr w tryb aktywny
status[4]=HAL_I2C_Mem_Read(&hi2c1, 0x98, 0x11, 1, &polozenie_l, 1, 100);
status[5]=HAL_I2C_Mem_Read(&hi2c1, 0x98, 0x12, 1, &polozenie_h, 1, 100);
polozenie = ((polozenie_h << 8) | polozenie_l);
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
https://i.stack.imgur.com/sgBnY.png
https://i.stack.imgur.com/itOLC.png
https://i.stack.imgur.com/4Y7Kp.png
https://i.stack.imgur.com/5PlLW.png
I would like to have a USB Joystick that is connected to a PIC microcontroller.
It works fine with just one throttle and several buttons and two axis.
How can I add another throttle descriptor ?
Here is the current one
const unsigned int USB_VENDOR_ID = 0x1234;
const unsigned int USB_PRODUCT_ID = 0x0001;
const char USB_SELF_POWER = 0x80; // Self powered 0xC0, 0x80 bus powered
const char USB_MAX_POWER = 50; // Bus power required in units of 2 mA
const char HID_INPUT_REPORT_BYTES = 64;
const char HID_OUTPUT_REPORT_BYTES = 64;
const char EP_IN_INTERVAL = 1;
const char EP_OUT_INTERVAL = 1;
// diske noconst char EP_IN_INTERVAL = 1;
const char USB_INTERRUPT = 0;
const char USB_TRANSFER_TYPE = 0x03; //0x03 Interrupt
const char USB_HID_EP = 1;
const char USB_HID_RPT_SIZE = 78;
/* Device Descriptor */
const struct {
char bLength; // bLength - Descriptor size in bytes (12h)
char bDescriptorType; // bDescriptorType - The constant DEVICE (01h)
unsigned int bcdUSB; // bcdUSB - USB specification release number (BCD)
char bDeviceClass; // bDeviceClass - Class Code
char bDeviceSubClass; // bDeviceSubClass - Subclass code
char bDeviceProtocol; // bDeviceProtocol - Protocol code
char bMaxPacketSize0; // bMaxPacketSize0 - Maximum packet size for endpoint 0
unsigned int idVendor; // idVendor - Vendor ID
unsigned int idProduct; // idProduct - Product ID
unsigned int bcdDevice; // bcdDevice - Device release number (BCD)
char iManufacturer; // iManufacturer - Index of string descriptor for the manufacturer
char iProduct; // iProduct - Index of string descriptor for the product.
char iSerialNumber; // iSerialNumber - Index of string descriptor for the serial number.
char bNumConfigurations; // bNumConfigurations - Number of possible configurations
} device_dsc = {
0x12, // bLength
0x01, // bDescriptorType
0x0200, // bcdUSB
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
8, // bMaxPacketSize0
USB_VENDOR_ID, // idVendor
USB_PRODUCT_ID, // idProduct
0x0020, // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
0x01 // bNumConfigurations
};
/* Configuration 1 Descriptor */
const char configDescriptor1[]= {
// Configuration Descriptor
0x09, // bLength - Descriptor size in bytes
0x02, // bDescriptorType - The constant CONFIGURATION (02h)
0x29,0x00, // wTotalLength - The number of bytes in the configuration descriptor and all of its subordinate descriptors
1, // bNumInterfaces - Number of interfaces in the configuration
1, // bConfigurationValue - Identifier for Set Configuration and Get Configuration requests
0, // iConfiguration - Index of string descriptor for the configuration
USB_SELF_POWER, // bmAttributes - Self/bus power and remote wakeup settings
USB_MAX_POWER, // bMaxPower - Bus power required in units of 2 mA
// Interface Descriptor
0x09, // bLength - Descriptor size in bytes (09h)
0x04, // bDescriptorType - The constant Interface (04h)
0, // bInterfaceNumber - Number identifying this interface
0, // bAlternateSetting - A number that identifies a descriptor with alternate settings for this bInterfaceNumber.
2, // bNumEndpoint - Number of endpoints supported not counting endpoint zero
0x03, // bInterfaceClass - Class code
0, // bInterfaceSubclass - Subclass code
0, // bInterfaceProtocol - Protocol code
0, // iInterface - Interface string index
// HID Class-Specific Descriptor
0x09, // bLength - Descriptor size in bytes.
0x21, // bDescriptorType - This descriptor's type: 21h to indicate the HID class.
0x01,0x01, // bcdHID - HID specification release number (BCD).
0x00, // bCountryCode - Numeric expression identifying the country for localized hardware (BCD) or 00h.
1, // bNumDescriptors - Number of subordinate report and physical descriptors.
0x22, // bDescriptorType - The type of a class-specific descriptor that follows
USB_HID_RPT_SIZE,0x00, // wDescriptorLength - Total length of the descriptor identified above.
// Endpoint Descriptor
0x07, // bLength - Descriptor size in bytes (07h)
0x05, // bDescriptorType - The constant Endpoint (05h)
USB_HID_EP | 0x80, // bEndpointAddress - Endpoint number and direction
USB_TRANSFER_TYPE, // bmAttributes - Transfer type and supplementary information
0x40,0x00, // wMaxPacketSize - Maximum packet size supported
EP_IN_INTERVAL, // bInterval - Service interval or NAK rate
// Endpoint Descriptor
0x07, // bLength - Descriptor size in bytes (07h)
0x05, // bDescriptorType - The constant Endpoint (05h)
USB_HID_EP, // bEndpointAddress - Endpoint number and direction
USB_TRANSFER_TYPE, // bmAttributes - Transfer type and supplementary information
0x40,0x00, // wMaxPacketSize - Maximum packet size supported
EP_OUT_INTERVAL // bInterval - Service interval or NAK rate
};
const struct {
char report[USB_HID_RPT_SIZE];
}
hid_rpt_desc =
{0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x09, 0x04, // USAGE (Joystick)
0xA1, 0x01, // COLLECTION (Application)
0x05, 0x02, // USAGE_PAGE (Simulation Controls)
0x09, 0xBB, // USAGE (Throttle)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data Var Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (Pointer)
0xA1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data Var Abs)}
0xC0, // END_COLLECTION
0x09, 0x39, // USAGE (Hat switch)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x03, // LOGICAL_MAXIMUM (3)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x46, 0x0E, 0x01, // PHYSICAL_MAXIMUM (270)
0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data Var Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x0A, // USAGE_MAXIMUM (Button 10)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x0C, // REPORT_COUNT (12) 2 bits added to switch report count
// so bytes are even. Bytes must be even.
0x55, 0x00, // UNIT_EXPONENT (0)
0x65, 0x00, // UNIT (None)
0x81, 0x02, // INPUT (Data Var Abs)
0xC0 // END_COLLECTION
};
//Language code string descriptor
const struct {
char bLength;
char bDscType;
unsigned int string[1];
} strd1 = {
4,
0x03,
{0x0409}
};
const struct{
//Manufacturer string descriptor
char bLength;
char bDscType;
unsigned int string[4];
}strd2={
10, //sizeof this descriptor string
0x03,
{'N','X','R','T'}
};
//Product string descriptor
const struct{
char bLength;
char bDscType;
unsigned int string[13];
}strd3={
28, //sizeof this descriptor string
0x03,
{'N','X','R','T','-','J','o','y','s','t','i','c','k'}
};
//Array of configuration descriptors
const char* USB_config_dsc_ptr[1];
//Array of string descriptors
const char* USB_string_dsc_ptr[3];
void USB_Init_Desc(){
USB_config_dsc_ptr[0] = &configDescriptor1;
USB_string_dsc_ptr[0] = (const char*)&strd1;
USB_string_dsc_ptr[1] = (const char*)&strd2;
USB_string_dsc_ptr[2] = (const char*)&strd3;
}
This is a multi-throttle descriptor that I've written for the ARDUINO Leonardo that shows multiple throttles on Windows 10. Please be aware though that Windows 10 only accepts 8 axis and 128 buttons per joystick device - so this descriptor will work with X, Y, Rudder, Left Brake, Right Brake, and 3 throttles max (I usually use 2)
I've collected all the USB HID values into #define values to make it more readable. (I'm not including those here). You can find the full library at https://github.com/Raptyr/FlightControl
uint8_t descriptor[150];
int descriptorIndex = 0;
#define DESCRIPTOR(_array,_index,label,value) _array[_index++] = label;_array[_index++] = value;
#define DESCRIPTOR1(_array,_index,label) _array[_index++] = label;
#define DESCRIPTOR3(_array,_index,label,value1,value2) _array[_index++] = label; _array[_index++] = value1;_array[_index++] = value2;
DESCRIPTOR(descriptor, descriptorIndex, USAGE_PAGE, PAGE_GENERIC_DESKTOP)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_JOYSTICK)
DESCRIPTOR(descriptor, descriptorIndex, COLLECTION, COLLECTION_APPLICATION)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_ID, _hidReportID)
if (_buttonCount > 0)
{
uint8_t buttonsInLastByte = _buttonCount % 8;
uint8_t paddingBits = buttonsInLastByte > 0 ? 8 - buttonsInLastByte : 0;
DESCRIPTOR(descriptor,descriptorIndex,USAGE_PAGE,PAGE_BUTTON)
DESCRIPTOR(descriptor,descriptorIndex,USAGE_MIN,01)
DESCRIPTOR(descriptor,descriptorIndex,USAGE_MAX,_buttonCount)
DESCRIPTOR(descriptor,descriptorIndex,LOGICAL_MIN,0)
DESCRIPTOR(descriptor,descriptorIndex,LOGICAL_MAX,1)
DESCRIPTOR(descriptor,descriptorIndex,REPORT_SIZE,1)
DESCRIPTOR(descriptor,descriptorIndex,REPORT_COUNT,_buttonCount)
DESCRIPTOR(descriptor,descriptorIndex,UNIT_EXP,0)
DESCRIPTOR(descriptor,descriptorIndex,UNIT,0)
DESCRIPTOR(descriptor,descriptorIndex,INPUT,IO_DATA | IO_VARIABLE | IO_ABSOLUTE)
if (paddingBits > 0)
{
DESCRIPTOR(descriptor,descriptorIndex,REPORT_SIZE,1)
DESCRIPTOR(descriptor,descriptorIndex,REPORT_COUNT,paddingBits)
DESCRIPTOR(descriptor,descriptorIndex,INPUT,IO_CONSTANT | IO_VARIABLE | IO_ABSOLUTE)
}
}
DESCRIPTOR(descriptor, descriptorIndex, USAGE_PAGE, PAGE_GENERIC_DESKTOP)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_POINTER)
DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MIN16, 0x01, 0x80)
DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MAX16, 0xFF, 0x7F)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_SIZE, 0x10)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_COUNT, _useBrakes ? 0x04 : 0x02)
DESCRIPTOR(descriptor, descriptorIndex, COLLECTION, COLLECTION_PHYSICAL)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_X)
DESCRIPTOR(descriptor, descriptorIndex, USAGE, GENERIC_Y)
if (_useBrakes)
{
DESCRIPTOR(descriptor, descriptorIndex,USAGE,GENERIC_RX)
DESCRIPTOR(descriptor, descriptorIndex,USAGE,GENERIC_RY)
}
DESCRIPTOR(descriptor, descriptorIndex, INPUT, IO_DATA | IO_VARIABLE | IO_ABSOLUTE)
DESCRIPTOR1(descriptor, descriptorIndex, END_COLLECTION)
if (_useRudder || _throttleCount > 0)
{
uint8_t simulationCount = (_useRudder ? 1 : 0) + _throttleCount;
DESCRIPTOR(descriptor, descriptorIndex, USAGE_PAGE, PAGE_SIMULATION_CONTROLS)
DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MIN16, 0x01, 0x80)
DESCRIPTOR3(descriptor, descriptorIndex, LOGICAL_MAX16, 0xFF, 0x7F)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_SIZE, 0x10)
DESCRIPTOR(descriptor, descriptorIndex, REPORT_COUNT, simulationCount)
DESCRIPTOR(descriptor, descriptorIndex, COLLECTION, COLLECTION_PHYSICAL)
if (_useRudder)
{
DESCRIPTOR(descriptor, descriptorIndex, USAGE, SIMULATION_RUDDER)
}
if (_throttleCount > 0)
{
for (uint8_t i = 0; i < _throttleCount; i++)
{
DESCRIPTOR(descriptor, descriptorIndex, USAGE, SIMULATION_THROTTLE)
}
}
DESCRIPTOR(descriptor, descriptorIndex, INPUT, IO_DATA | IO_VARIABLE | IO_ABSOLUTE)
DESCRIPTOR1(descriptor, descriptorIndex, END_COLLECTION)
}
DESCRIPTOR1(descriptor, descriptorIndex, END_COLLECTION)
I'm using an online CRC-32 calculator to check that my output is correct however it seems that Wireshark has a different expected FCS for the ethernet packet.
message2 is the ethernet frame minus the FCS as seen in Wireshark
#include <stdio.h>
#include <stdint.h>
unsigned int crc32b(unsigned char *message) {
int i, j;
unsigned int byte, crc, mask;
i = 0;
crc = 0xFFFFFFFF;
while (message[i] != 0) {
//printf("%i %x \n\n", i, message[i]);
byte = message[i];
crc = crc ^ byte;
for (j = 7; j >= 0; j--) {
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
i = i + 1;
}
return ~crc;
}
int main(void)
{
unsigned char * message = "hello test";
unsigned char * message2 = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";
unsigned int res = crc32b(message2);
printf("%x\n", res);
return 0;
}
I've tried using different Polynomials as defined in [1 - subsection CRC-32 IEEE 802.3], however the result does not match Wireshark.
Output using 0xED Polynomial: 0xd81e4af3
Wireshark FCS expected: 0xa8cd3084
I'd really like to code in the FCS for my ethhdr packet, I guess when creating a software packet, the FCS isn't entered by the NIC...
Sources:
[1] - http://crppit.epfl.ch/documentation/Hash_Function/WiKi/Cyclic_redundancy_check.htm
Your implementation is definitively correct (for NUL terminated C strings). It's a maybe a wrong configuration of the network interface. In default mode Wireshark doesn't get a FCS from the network driver. If you use Linux and the driver supports this, then you must enable this with ethtool to get the FCS.
Unfortunately, on my system this only works for receiving frames:
$ ethtool -K eth0 rx-fcs on
See this for details.
I use a slightly different algorithm in my embedded (for AVR microcontrollers) projects and it works perfectly for me:
#define CRC_POLY 0xEDB88320
uint32_t crc32_calc(uint8_t *data, int len)
{
int i, j;
uint32_t crc;
if (!data)
return 0;
if (len < 1)
return 0;
crc = 0xFFFFFFFF;
for (j = 0; j < len; j++) {
crc ^= data[j];
for (i = 0; i < 8; i++) {
crc = (crc & 1) ? ((crc >> 1) ^ CRC_POLY) : (crc >> 1);
}
}
return (crc ^ 0xFFFFFFFF);
}
A real world example:
The Ethernet frame in Wireshark (with ethtool rx-fcs on):
The test with my used implementation:
uint8_t frame[] = { 0x20, 0xcf, 0x30, 0x1a, 0xce, 0xa1, 0x62, 0x38,
0xe0, 0xc2, 0xbd, 0x30, 0x08, 0x06, 0x00, 0x01,
0x08, 0x00 ,0x06 ,0x04 ,0x00 ,0x01 ,0x62 ,0x38,
0xe0 ,0xc2 ,0xbd ,0x30 ,0x0a, 0x2a, 0x2a, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x2a,
0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
printf("0x%x\n", crc32_calc(frame, sizeof(frame)));
The output:
$ ./fcs-test
0x6026b722
$
You can see, Wireshark reports 0x22bf2660 as correct FCS. Here is only a different output because of the byte-order. But the CRC calculation algorithm is correct.
EDIT:
I have modified your code:
uint32_t crc32b(uint8_t *message, int len) {
int i, j;
uint32_t crc, mask;
uint8_t byte;
crc = 0xFFFFFFFF;
for (j = 0; j < len; j++) {
byte = message[j];
crc = crc ^ byte;
for (i = 7; i >= 0; i--) {
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~crc;
}
I added a length argument, because your implementation only works correct when message is a NUL terminated C string. If your input is a byte array, then you get a incorrect CRC value.
See the differences (Array and C string):
uint8_t msg_arr[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x5c, 0xb9, 0x01, 0x7c, 0x5a, 0x53, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
char *msg_str = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";
printf("0x%x\n", crc32b(msg_arr, sizeof(msg_arr)));
printf("0x%x\n", crc32b(msg_str, strlen(msg_str)));
Output:
$
0x3422dd71
0xd81e4af3
$
There are a number of problems with your code. There are also plenty of existing implementations you could compare (eg, this one linked from the real Wikipedia page on CRC).
unsigned char * message2 = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";
Are you hoping that this will be the octet sequece 0xAA 0xBB 0xCC ... as you see them in Wireshark? Because that isn't at all what you have.
This string actually contains 0x61 0x61 0x62 0x62 ... (assuming your platform uses ASCII encoding) because it is a character string and not an octet string.
specifically, here: byte = message[i]; you assume the first 8 bits of your message are an octet, and again I assume since you didn't say, that you expected this to be 0xAA. It will actually be 0x61.
If you want this to work correctly, translate each pair of characters into an integer value using strtoul(pair, NULL, 16) or similar.
You have a loop for (j = 7; j >= 0; j--) but never use j inside it. You do use the integer constant 1 in an odd-looking way: is there supposed to be a (1 << j) or something?
I suggest fixing the obvious errors, and then writing some self-contained tests before you try comparing whole frames with Wireshark. The code you posted has some basic errors that should be tested, identified and fixed before you get to this point.
Im not sure about your question, but if you want calculate a checksum of a network packet, you have to deploy the data in it's proper structure.
Please make sure your problem is not related with endianness.
The network byte-order is big-endian, here is the point that the things getting a little bit harder.
Little-Endian mostly used in PCs but may vary by hardware and manufacturer.
2byte integer (16 bit integer) with value 255.
Little Endian: FF00
Big Endian: 00FF
Im not sure what kind of checksum you are trying to match with, but checksum not only for data field, mostly it contains all flags and options, issued at last step thats why the implementation require the corresponding data structure.
About checksums, there are a lot of case when you get an invalid checksum with wireshark, it could cause kernel, virtual adapter, accelerated network, dedicated CPU in your NIC, etc...
Example for TCP header:
/* include/linux/tcp.h */
struct tcphdr {
__u16 source;
__u16 dest;
__u32 seq;
__u32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__u16 window;
__u16 check;
__u16 urg_ptr;
};
For a few days I have been trying to get the correct answer from the PS2 gamepad (DualShock 2) on the STM32F411RE Nucleo.
I use SPI and USART to receive messages.
The clock frequency is set to 8 MHz and the SPI prescaler to a 64 configuration which gives me 125 kHz (kbit/s).
The first bit is taken from LSB, the CPOL parameter at 1, and CPHA on 2. It is NSS software controlled, set to GPIO output (PA4-CS pin). I use PA5 pins as SCK (clock) PA6-MISO, PA7-MOSI. SPI is set to full-duplex master mode. (USART asynchronous and 9600 bit/s, but it's just for receiving messages on a PC).
The microcontroller operates a HAL library.
In the main.c file:
#define CS_LOW HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET)
#define CS_HIGH HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET)
CS LOW - sets the line "attention" to state 0 and CS_HIGH to state 1.
The function sending command and return data (MISO-MOSI):
uint8_t PS2_RWByte(uint8_t komenda, uint8_t tablica, int wielkosc)
{
HAL_SPI_Transmit(&hspi1, &komenda, sizeof(komenda), 1);
HAL_SPI_Receive(&hspi1, &tablica, sizeof(tablica), 1);
return(tablica);
}
Function sending a byte string:
uint8_t Get_PS2Dat(uint8_t buf[])
{
CS_LOW;
HAL_Delay(15/1000);
buf[0] = PS2_RWByte(0x01, buf[0], 8);HAL_Delay(15/1000);
buf[1] = PS2_RWByte(0x42, buf[1], 8);HAL_Delay(15/1000);
buf[2] = PS2_RWByte(0x00, buf[2], 8);HAL_Delay(15/1000);
buf[3] = PS2_RWByte(0x00, buf[3], 8);HAL_Delay(15/1000);
buf[4] = PS2_RWByte(0x00, buf[4], 8);HAL_Delay(15/1000);
buf[5] = PS2_RWByte(0x00, buf[5], 8);HAL_Delay(15/1000);
buf[6] = PS2_RWByte(0x00, buf[6], 8);HAL_Delay(15/1000);
buf[7] = PS2_RWByte(0x00, buf[7], 8);HAL_Delay(15/1000);
buf[8] = PS2_RWByte(0x00, buf[8], 8);HAL_Delay(15/1000);
CS_HIGH;
if((buf[0] == 0xFF) && (buf[1] == 0x41) && (buf[2] == 0x5A))
return 1;
if((buf[0] == 0xFF) && (buf[1] == 0x73) && (buf[2] == 0x5A))
return 2;
return 0;
}
In the main function:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_SPI1_Init();
HAL_SPI_MspInit(&hspi1);
uint8_t PS2buf[10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t wyswietl[30] = {0};
while (1)
{
Get_PS2Dat(PS2buf);
for(int i=0; i<9; i++)
{
sprintf(wyswietl, "%u ,", PS2buf[i]);
HAL_UART_Transmit(&huart2, wyswietl, 30, 250);
}
sprintf(wyswietl, "\n\r");
HAL_UART_Transmit(&huart2, wyswietl, 30, 250);
HAL_Delay(300);
}
}
After sending the information: 0x01 0x42 0x00 0x00 0x00 I should get 0xFF 0x41 0x5A 0xFF 0xFF if no button is pressed.
At 3 and 4 bytes should appear information about the pressed keys while I get such values:
65, 255, 255, 255, 255 ie 0xFF 0xFF 0xFF 0xFF 0xFF.
It is strange how the second sent byte corresponds to the first received. The additional point is that if you press the "mode" key the value 65 changes to 115 (0x73), while others still remain unchanged.
You should use HAL_SPI_TransmitReceive instead of a combination of HAL_SPI_Transmit and HAL_SPI_Receive.
The function HAL_SPI_Transmit only sends data and omits incoming bytes.
The function HAL_SPI_Receive sends dummy data and fetches incoming bytes.
Basically, you are receiving every second character.
65 = 0x42 is the second character. Because you send a dummy byte when you receive data, the remaining message is not understood by the PS2 controller, so you get 0xFF.
Change your PS2_RWByte function like that and it should work:
uint8_t PS2_RWByte(uint8_t komenda, uint8_t tablica, int wielkosc)
{
HAL_SPI_TransmitReceive(&hspi1, &komenda, &tablica, sizeof(uint8_t), 1);
return(tablica);
}
I am not familiar with the PS2 gamepad, but I believe you have to set the NSS pin back to high after your spi-receive (so you need also set it to low before every single write...).
I am writing a DAC driver for the Freedom KL25z and it does not work. I am testing it with an oscilloscope, but there is no rise in voltage.
My configuration function is using the only DAC channel available for the KL25...
Connected oscilloscope voltage to PORTE30 pin and oscilloscope ground to KL25 GND pin.
UPDATE, forgot to write filenames and actual question
Here is my DACDriver.c file
#include "DACDriver.h"
unsigned char bflgSendingData = 0;
unsigned short* wpSetPattern;
unsigned short wSetPatternSize;
void vfnDACInit()
{
SIM_SCGC6 |= SIM_SCGC6_DAC0_MASK;
DAC0_C0 |= DAC_C0_DACRFS_MASK;
PORTE_PCR30 = PORT_PCR_MUX(0);
DAC0_DAT0L = 0x00;
DAC0_DAT0H |= 0x0;
DAC0_DAT1L = 0xFF;
DAC0_DAT1H |= 0xF;
DAC0_C0 |= DAC_C0_DACEN_MASK;
}
void vfnDACSetValue(unsigned short wValue)
{
DAC0_DAT0L = (unsigned char)(wValue & 0xFF);
DAC0_DAT0H = (unsigned char)(wValue >> 8);
}
unsigned char bfnDACDriver(void)
{
vfnDACSetValue(0xFF);
/*This is just a test; in my main, I'm just trying to see an output here.
But the main logic should be like the code below*/
/*if(bflgSendingData){
if(wSetPatternSize){
vfnDACSetValue(wpSetPattern);
wpSetPattern++;
wSetPatternSize--;
}
return 1;
}else{
return 0;
}
*/
}
unsigned char bfnDACSetPattern(unsigned short* wpPattern, unsigned short wPatternSize)
{
if(0 == bflgSendingData){
wpSetPattern = wpPattern;
wSetPatternSize = wPatternSize;
bflgSendingData = 1;
return 1;
}else{
return 0;
}
}
UPDATE, forgot to include this file
Here is my DACDriver.h file
#ifndef __DACDRIVER_H_
#define __DACDRIVER_H_
#include "derivative.h"
void vfnDACInit(void);
unsigned char bfnDACDriver(void);
unsigned char bfnDACSetPattern(unsigned short* wpPattern, unsigned short wPatternSize);
#endif /* __DACDRIVER_H_ */
Here is my main.c file, which right now only has a little test so I can see some output
#include "DACDriver.h"
int main(void)
{
unsigned char pattern[] = {
0xFF, 0xEF, 0xDF, 0xCF, 0xBF, 0xAF,
0x9F, 0x8F, 0x7F, 0x6F, 0x5F, 0x4F, 0x3F, 0x2F, 0x1F,
0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A,
0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
vfnDACInit();
for(;;) {
bfnDACDriver();
}
return 0;
}
I am trying to be the most autodidact possible, but I have run out of ideas...
My main questions are:
Do you see any error here?
How do I make it work?
Am I missing something?
Thanks a lot!!
So my real problem was not seeing that my oscilloscope didn't have the right voltage/time resolution hence the "null" output so to speak. My driver is fine. Thank you very much to everyone answering and taking an interest in my problem.