STM32 F411RE Nucleo SPI support and programming the PlayStation 2 controller - c

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...).

Related

LibOpenCM3 1-Wire over UART DMA STM32F1

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.

C - CRC32 checksum does not match Wireshark on Ethernet Frame Check Sequence

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;
};

STM32 LwIP netconn_write problem transmitting structs

I am using LwIP stack with FreeRTOS in STM32F407Discovery board as TCP Client and I have a Linux computer as TCP Server. I faced a problem during transmission of a struct array, say struct EncoderData Encoder[2], through netconn API.
The thing is, when I print the elements of the struct array to Serial Terminal (with UART) the data stored in the struct array is correctly shown. However when I send the structs through netconn socket, the elements of the first struct, i.e. Encoder[0] is received correctly, whereas Encoder[1] is received as all zeroes.
Expected output in the Server side,
Encoder[0] ---> 0xAA 0x07 0x00 0x52 0x12 0xDC 0xAB 0xFA
Encoder[1] ---> 0xAA 0x07 0x01 0x52 0x42 0xBF 0xAA 0xFA
Resulting problematic output in the Server side
Encoder[0] ---> 0xAA 0x07 0x00 0x52 0x12 0xDC 0xAB 0xFA
Encoder[1] ---> 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Below, I am sharing both the server and the client side code, I would appreciate if you could help me out identifying the problem.
Server.c -- Linux Computer
#define MAX 9
#define PORT 8080
#define SA struct sockaddr
#define NUM_OF_ENCODERS 2
#define PREAMBLE 0xAA
#define LENGTH 0x07
#define CRC 0xFA
struct EncoderData {
volatile uint8_t encoderID;
volatile uint8_t byte0;
volatile uint8_t byte1;
volatile uint8_t byte2;
volatile uint8_t byte3;
volatile uint8_t byte4;
volatile uint32_t singleTurnValue;
volatile uint16_t multiTurnValue;
volatile uint16_t prevMultiTurnValue;
volatile uint8_t direction;
volatile float angle;
};
struct EncoderData Encoder[NUM_OF_ENCODERS];
// This function is called inside int main()
void func(int sockfd)
{
uint8_t buff[MAX];
uint32_t singleTurnValue = 0;
float angle = 0.0;
uint8_t channel;
uint8_t encoderID;
// infinite loop to read data continuously
for (;;) {
bzero(buff, MAX);
// read the message from client and copy it in buffer
read(sockfd, buff, sizeof(buff));
if(buff[0] == PREAMBLE && buff[1] == LENGTH && buff[8] == CRC)
{
encoderID = buff[2];
Encoder[encoderID].encoderID = encoderID;
Encoder[encoderID].byte0 = (uint8_t)buff[3];
Encoder[encoderID].byte1 = (uint8_t)buff[4];
Encoder[encoderID].byte2 = (uint8_t)buff[5];
Encoder[encoderID].byte3 = (uint8_t)buff[6];
Encoder[encoderID].byte4 = (uint8_t)buff[7];
Encoder[encoderID].singleTurnValue = (uint32_t)((buff[5] << 16)|(buff[6] << 8)|(buff[7]));
Encoder[encoderID].multiTurnValue = (uint16_t)((buff[3] << 8)|(buff[4]));
//printf("%d\n", encoderID);
bzero(buff, MAX);
}
// Here I print the struct elements, below printf shows data correctly
printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\t\t",
Encoder[0].encoderID, Encoder[0].byte0, Encoder[0].byte1,
Encoder[0].byte2, Encoder[0].byte3, Encoder[0].byte4);
// However below printf results in only zeroes
printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",
Encoder[1].encoderID, Encoder[1].byte0, Encoder[1].byte1,
Encoder[1].byte2, Encoder[1].byte3, Encoder[1].byte4);
}
}
Client.c -- STM32F407Discovery
#define NUM_OF_ENCODERS 2
struct EncoderData Encoder[NUM_OF_ENCODERS];
void Encoder_Process(void)
{
//float angle = 0.0;
uint64_t encoderRawValue = 0;
uint32_t singleTurnValue = 0;
uint8_t channel = 0;
for(channel = 0; channel < NUM_OF_ENCODERS; channel++)
{
selectChannel(channel);
encoderRawValue = readEncoder();
singleTurnValue = getSingleTurn(encoderRawValue);
angle = calculateMotorAngle(singleTurnValue);
Encoder[channel].preamble = 0xAA;
Encoder[channel].length = 0x07;
Encoder[channel].encoderID = channel;
Encoder[channel].byte0 = (uint8_t)((encoderRawValue >> 32) & 0xFF);
Encoder[channel].byte1 = (uint8_t)((encoderRawValue >> 24) & 0xFF);
Encoder[channel].byte2 = (uint8_t)((encoderRawValue >> 16) & 0xFF);
Encoder[channel].byte3 = (uint8_t)((encoderRawValue >> 8) & 0xFF);
Encoder[channel].byte4 = (uint8_t)((encoderRawValue ) & 0xFF);
Encoder[channel].crc = 0xFA;
}
}
// Convert Encoder struct into buffer
uint8_t* prepareEncoderData(struct EncoderData enc)
{
static uint8_t buffer[9];
memset(buffer, '\0', 9);
buffer[0] = enc.preamble;
buffer[1] = enc.length;
buffer[2] = enc.encoderID;
buffer[3] = enc.byte0;
buffer[4] = enc.byte1;
buffer[5] = enc.byte2;
buffer[6] = enc.byte3;
buffer[7] = enc.byte4;
buffer[8] = enc.crc;
return buffer;
}
static void tcp_client_netconn_thread(void *arg)
{
struct netconn *conn; //, *newconn;
struct ip_addr remoteipaddr, localipaddr;
err_t err1, err2;
// portCHAR pagehits[100] = {0};
uint8_t channels;
uint8_t *transmitBuffer;
IP4_ADDR(&remoteipaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3);
IP4_ADDR(&localipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
/* Create a new TCP connection handle */
conn = netconn_new(NETCONN_TCP);
if (conn!= NULL)
{
err1 = netconn_bind(conn, &localipaddr, PORT_NUMBER);
err2 = netconn_connect(conn, &remoteipaddr, PORT_NUMBER);
if (err1 == ERR_OK && err2 == ERR_OK)
{
printf("STM32F4 connected to the server!\n");
while(1)
{
for(channels = 0; channels < NUM_OF_ENCODERS; channels++)
{
Encoder_Process();
transmitBuffer = prepareEncoderData(Encoder[channels]);
netconn_write(conn, transmitBuffer, strlen((char*)transmitBuffer), NETCONN_COPY);
}
vTaskDelay(10);
//netconn_delete(newconn);
}
}
else
{
printf("can not bind netconn");
printf("\terr code: %d", err1);
printf("\terr code: %d\n", err2);
}
}
else
{
printf("can not create netconn");
}
}

How to stop I2C communication when you are recieving a data from slave?

I am implementing I2C communication protocol. I am sending 5 bytes of data to a slave device (slave address is 0x48). and Then want to see the response.
I am getting my desired response, but the only problem I am facing is that I am not able to stop this communication.
For example, I send 5 bytes of data, and in response I am expecting 3 bytes of data. I get this data but after that I don't see any stop condition. And due to that I cannot send further data to my slave device.
I am checking my results with logic analyzer, and in logic analyzer it shows unknown after receiving 3 bytes. (Images attached).
It seems like I am not properly starting and stopping the I2C communication.
The code I have written is given below:
#include <msp430.h>
char TXData[5] = { 0x5A, 0xCF, 0x00 }; //Data to be transmitted
//unsigned char TXData[] = { 0x5A, 0x40, 0x09, 0x80, 0x04, 0x00, 0x22, 0x03, 0x41, 0x01, 0x01, 0x04, 0xE5, 0xEF }; // GetMemory APDU
//unsigned char TXData[] = { 0x5A, 0x00, 0x0B, 0x80, 0x04, 0x00, 0x1B, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x0A, 0xEE, 0x07 }; // CreateSession APDU
//unsigned char TXData[] = { 0x5A, 0x00, 0x16, 0x00, 0xA4, 0x04, 0x00, 0x10, 0xA0, 0x00, 0x00, 0x03, 0x96, 0x54, 0x53, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC8 }; // GetVersion APDU
volatile unsigned char RXData[3]; // To save the received data
unsigned char SlaveAddress = 0x48; // slave address
volatile unsigned char TXByteCtr;
volatile unsigned char TxByteCnt = 0;
volatile unsigned char RxByteCnt = 0;
unsigned char Rx; // To enable reception
void Transmit(void);
void Recieve(void);
short crc_ret;
//short final;
unsigned short crc16_x25(char* pData, int length)
{
int i;
unsigned short wCrc = 0xffff;
while (length--) {
wCrc ^= *(unsigned char *)pData++ << 0;
for (i=0; i < 8; i++)
wCrc = wCrc & 0x0001 ? (wCrc >> 1) ^ 0x8408 : wCrc >> 1;
}
return wCrc ^ 0xffff;
}
int main(void)
{
WDTCTL = WDTPW | WDTHOLD;
//while(1);
// Configure GPIO
P8OUT |= BIT0; // Clear P8.0 output latch
P8DIR |= BIT0;
P7SEL0 |= BIT0 | BIT1;
P7SEL1 &= ~(BIT0 | BIT1);
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
// Configure USCI_B2 for I2C mode
UCB2CTLW0 |= UCSWRST; // put eUSCI_B in reset state
UCB2CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK; // I2C master mode, SMCLK
UCB2BRW = 0x8; // baudrate = SMCLK / 8
UCB2CTLW0 &= ~UCSWRST; // clear reset register
UCB2IE |= UCTXIE0 | UCNACKIE | UCRXIE0; // transmit, Receive and NACK interrupt enable
crc_ret = crc16_x25(TXData, (sizeof(TXData) - 2)); // Calling CRC function
TXData[3] = (char)crc_ret;
TXData[4] = (char)((crc_ret&0xFF00)>>8);
while(1)
{
__delay_cycles(2000); // Delay between transmissions
UCB2I2CSA = SlaveAddress; // configure slave address
TXByteCtr = 1; // Load TX byte counter
Transmit(); //Implementing the transmit function
__delay_cycles(2000);
Rx = 1;
Recieve(); //Implementing the receive function
__delay_cycles(2000);
}
}
#pragma vector = EUSCI_B2_VECTOR
__interrupt void USCI_B2_ISR(void)
{
switch(__even_in_range(UCB2IV, USCI_I2C_UCBIT9IFG))
{
case USCI_NONE: break; // Vector 0: No interrupts
case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG
UCB2CTLW0 |= UCTXSTT; // resend start if NACK
break;
case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG
case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG
case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3
case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3
case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2
case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2
case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1
case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1
case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0
if (Rx < 3) // Check RX byte counter
{
RXData[RxByteCnt]= UCB2RXBUF; // Load TX buffer
RxByteCnt++;
Rx++; // Decrement TX byte counter
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
else
{
UCB2CTLW0 |= UCTXSTP; // I2C stop condition
UCB2IFG &= ~UCRXIFG; // Clear USCI_B2 RX int flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
break;
case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0
if (TXByteCtr < (sizeof(TXData) + 1)) // Check TX byte counter
{
UCB2TXBUF = TXData[TxByteCnt]; // Load TX buffer
TxByteCnt++;
TXByteCtr++; // Decrement TX byte counter
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
else
{
TxByteCnt = 0;
UCB2CTLW0 |= UCTXSTP; // I2C stop condition
UCB2IFG &= ~UCTXIFG; // Clear USCI_B2 TX int flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
break;
case USCI_I2C_UCBCNTIFG: break; // Vector 26: BCNTIFG
case USCI_I2C_UCCLTOIFG: break; // Vector 28: clock low timeout
case USCI_I2C_UCBIT9IFG: break; // Vector 30: 9th bit
default: break;
}
}
void Transmit(void)
{
while (UCB2CTLW0 & UCTXSTP); // Ensure stop condition got sent
UCB2CTLW0 |= UCTR | UCTXSTT; // I2C TX, start condition
__bis_SR_register(GIE); // Enter LPM0 w/ interrupts
// Remain in LPM0 until all data
// is TX'd
}
void Recieve(void)
{
while (UCB2CTLW0 & UCTXSTP); // Ensure stop condition got se
UCB2CTLW0 &= ~UCTR;
UCB2CTLW0 |= UCTXSTT;
__bis_SR_register(GIE); // Enter LPM0 w/ interrupts//start condition;
// I2C stop condition
UCB2CTLW0 &= ~UCTXSTP;
//UCB2IFG &= ~UCRXIFG;
}
And the transmitted and received data is also attached:
You can see in the received data, that after 3 bytes, there is written "unknown". Due to this unknown thing, I am not able to send further data.
I shall be very thankful if someone can help me out in this.
Thank you

Arduino WiServer relay control - can't get relay to switch

I am working on a sketch to help set up a remote door opener, based on the result of a web call. I've got a BlackWidow Arduino running WiServer, and the wifi works fine and I can get a result from my URL. I'm simply returning a 0 or 1 as the content.
The problem is in my loop the relayControlState is always HIGH, and I can't seem to get the loop to make the relay turn off/on.
When I just use a simple "blinker" sketch I can get the relay to work fine, it's only when it's intertwined with my server fetch code that it doesn't work. What am I missing? Code is below. Why does relayControlState not update inside the WiServer.getStatus callback? Is the relay not getting enough juice to switch?
#include <WiServer.h>
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,1,10}; // IP address of WiShield 192.168.1.10
unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
char ssid[] = {"monitored"}; // max 32 bytes
unsigned char security_type = 3; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"password"}; // max 64 characters
// setup the wireless mode
// infrastructure - connect to AP
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
// IP Address for macpro.local
uint8 ip[] = {192,168,1,12};
// End of wireless configuration parameters ----------------------------------------
// A request that gets the aggregate status of the build system
GETrequest getStatus(ip, 80, "macpro.local", "/open-says-me/index.html");
const int relayPin = 12;
int relayControlState = HIGH;
// Function that sets pin/light states
// BEWARE: THIS FUNCTION IS CALLED MULTIPLE (2) TIMES PER HTTP REQ
// Hidden call before/after call that returns payload 0, 1, 2, or null
void setRelayControlState(char* data, int len) {
// Serial.print("=========================\n\nLEN:\n");
// Serial.print(len);
if(len > 0) {
Serial.print("\nDATA:");
Serial.print(data[len - 1]);
Serial.print("\n");
// Serial.print("\n\nsetRelayControlState\n\n");
if(data[len - 1] == '0') {
relayControlState = LOW;
Serial.print("SET LOW");
}
if(data[len-1] == '1') {
relayControlState = HIGH;
Serial.print("SET HIGH");
}
} else {
relayControlState = LOW;
}
}
void setup() {
pinMode(relayPin, OUTPUT);
Serial.begin(57600);
// Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages)
WiServer.init(NULL);
// Enable Serial output and ask WiServer to generate log messages (optional)
WiServer.enableVerboseMode(true);
// Have the processData function called when data is returned by the server
getStatus.setReturnFunc(setRelayControlState);
}
// Time (in millis) when the data should be retrieved
long updateTime = 0;
void loop(){
// Check if it's time to get an update
if (millis() >= updateTime) {
// Get another update 15s from now
updateTime += 1000 * 5;
getStatus.submit();
}
// Run WiServer
WiServer.server_task();
// turn on light pins based on stored vals
Serial.print("\nrelayControlState: ");
Serial.print(relayControlState);
Serial.print("\n");
digitalWrite(relayPin, relayControlState);
delay(10);
}
This is the code that worked in the end, but it also could have just been inconsistent behavior of the code loading onto the BlackWidow. I started to switch pins - each time I switched to try a new pin, it would work once, but only once, until I started power cycling the arduino. Seems it likes a power down instead of only a reset or new code upload. Still a bit finicky, but a working example of polling a URL for a specific last character. If 1 set pin high for 5.5 seconds. If 0 do nothing.
#include <WiServer.h>
// ---------------------------------------------------------------------------------
// Wireless configuration parameters
// ---------------------------------------------------------------------------------
unsigned char local_ip[] = {192,168,1,10}; // IP address of WiShield 192.168.1.10
unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
char ssid[] = {"monitored"}; // max 32 bytes
// 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
unsigned char security_type = 3;
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"password"}; // max 64 characters
// WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, // Key 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};
// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
// ---------------------------------------------------------------------------------
// GET REQUEST
// ---------------------------------------------------------------------------------
// IP Address for macpro.local
uint8 ip[] = {192,168,1,12};
// The request URL
GETrequest getStatus(ip, 80, "macpro.local", "/open-says-me/index.html");
const int relayPin = 3;
int relayControlState = LOW;
// ---------------------------------------------------------------------------------
// Callback for WiServer's getStatus
// ---------------------------------------------------------------------------------
void setRelayControlState(char* data, int len) {
Serial.print("[setRelayControlState] last digit of data: ");
Serial.println(data[len-1]);
Serial.print("[setRelayControlState] len: ");
Serial.println(len);
if(len > 0
&& data[len-1] == '1') {
relayControlState = HIGH;
Serial.print("\nSET HIGH FOR 5.5s\n");
digitalWrite(relayPin, HIGH);
delay(5500);
digitalWrite(relayPin, LOW);
}
}
void setup() {
pinMode(relayPin, OUTPUT);
Serial.begin(57600);
// Initialize WiServer (we'll pass NULL for the page serving function since we don't need to serve web pages)
WiServer.init(NULL);
// Enable Serial output and ask WiServer to generate log messages (optional)
WiServer.enableVerboseMode(true);
// Have the processData function called when data is returned by the server
getStatus.setReturnFunc(setRelayControlState);
}
// Time (in millis) when the data should be retrieved
long updateTime = 0;
void loop(){
// Check if it's time to get an update
if (millis() >= updateTime) {
// Get another update 15s from now
updateTime += 1000 * 15;
getStatus.submit();
Serial.print("end update # ms ");
Serial.println(millis());
}
WiServer.server_task();
delay(100);
}

Resources