STM32 UART DMA can receive first time correct then it receive nothing - stm32

I'm trying to use dma with uart in stm32f746 nucleo.
In receiving mode I can receive correct data in first use. When i try to receive again, receiving buffer doesn't change its initial values before receiving although I can get receive complete signal callback every time.
/* Main Loop */
while(1)
{
HAL_GPIO_TogglePin(LED_PORT,LED_GREEN); // Led Example
HAL_Delay(200);
pRxData[0]=5;
pRxData[1]=0;
// HAL_UART_Receive_IT(&UartHandle,pRxData,2);
if( HAL_UART_Receive_DMA(&UartHandle,pRxData,2)==HAL_OK); // UART-DMA-IT Example
{
while (UartReady != SET) // wait for msg len
{
HAL_GPIO_WritePin(LED_PORT,LED_GREEN,1);
HAL_Delay(20);
HAL_GPIO_WritePin(LED_PORT,LED_GREEN,0);
HAL_Delay(400);
}
UartReady = RESET; // reset transmition flag
LEN = pRxData[0]+pRxData[1]*256; // calc msg length
if ( LEN > 0 )
{
pTxData[0]= 25;//LEN; // ACK
//HAL_UART_Transmit_IT(&UartHandle,pTxData,1);
if(HAL_UART_Transmit_DMA(&UartHandle,pTxData,1)==HAL_OK);
{
while (UartReady != SET)
{
HAL_Delay(1);
}
UartReady = RESET;
if(HAL_UART_Receive_IT(&UartHandle,pRxData,LEN)==HAL_OK)
{
//HAL_UART_Receive_DMA(&UartHandle,pRxData,LEN);
while (UartReady != SET) // waiting loop for msg
{
HAL_GPIO_WritePin(LED_PORT,LED_GREEN,1);
HAL_Delay(300);
HAL_GPIO_WritePin(LED_PORT,LED_GREEN,0);
HAL_Delay(50);
}
UartReady = RESET;
if (MBU_StrCompareNC(pRxData,"LED_ON_BLUE",LEN)==0)
{
HAL_GPIO_WritePin(LED_PORT,LED_BLUE,1);
}
if (MBU_StrCompareNC(pRxData,"LED_OFF_BLUE",LEN)==0)
{
HAL_GPIO_WritePin(LED_PORT,LED_BLUE,0);
}
if (MBU_StrCompareNC(pRxData,"LED_ON_RED",LEN)==0)
{
HAL_GPIO_WritePin(LED_PORT,LED_RED,1);
}
if (MBU_StrCompareNC(pRxData,"LED_OFF_RED",LEN)==0)
{
HAL_GPIO_WritePin(LED_PORT,LED_RED,0);
}
}
HAL_UART_Abort(&UartHandle);
}
}
}
}
}

Related

I2C EK-TM4C129EXL: Reads bytes double

I'm trying to communicate on an TI launchpad via i2c with a GPS Receiver. The Launchpad I use is the EK-TM4C129EXL. For the initialization and the communication aim using the TIVA ware Library. The TI Launchpad is the Master and the GPS receiver is the Slave.
This is the Init function I use:
SYS_RESLT sys_I2cInitFunc(uint32_t g_ui32SysClock){
SYS_RESLT eFault = SYS_RESLT__OK;
//
// Stop the Clock, Reset and Enable I2C Module
// in Master Function
//
SysCtlPeripheralDisable(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralReset(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
//
// Wait for the I2C0 module to be ready.
//
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C0))
{
}
//
//Enable GPIO for Configuring the I2C Interface Pins
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
//
// Wait for the Peripheral to be ready for programming
//
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB))
{
};
//
// Configure Pins for I2C2 Master Interface
//
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2C(GPIO_PORTB_AHB_BASE, GPIO_PIN_3);
GPIOPinTypeI2CSCL(GPIO_PORTB_AHB_BASE, GPIO_PIN_2);
//
// Initialize Master
//
I2CMasterInitExpClk(I2C0_BASE,g_ui32SysClock, false);
return eFault;}
the Parameter g_ui32SysClock is the System Clock frequency.
Then I have a Function which I use to read.
SYS_RESLT gps_readByteI2C(uint8_t *pbBytesRead, uint8_t bLen){
SYS_RESLT eFault = SYS_RESLT__OK;
uint8_t bAdd = GPS_I2C_ADD
;
uint8_t bI = 0;// read only one byte
if (bLen == 1){ // wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// set i2c address and read
I2CMasterSlaveAddrSet(I2C0_BASE, bAdd, true);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// read on the bus
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// check fault
if (I2CMasterErr(I2C0_BASE) != I2C_MASTER_ERR_NONE)
{
eFault = SYS_RESLT__I2C; // fault
}
while (I2CMasterBusy(I2C0_BASE))
{
}
// read data
*pbBytesRead = I2CMasterDataGet(I2C0_BASE);
}
else // more then one byte to read
{
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// set i2c address and read
I2CMasterSlaveAddrSet(I2C0_BASE, bAdd, true);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// read on the bus first byte
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// check fault
if (I2CMasterErr(I2C0_BASE) != I2C_MASTER_ERR_NONE)
{
//test = I2CMasterErr(I2C0_BASE);
eFault = SYS_RESLT__I2C; // fault
}
while (I2CMasterBusy(I2C0_BASE))
{
}
// get data
pbBytesRead[0] = I2CMasterDataGet(I2C0_BASE);
// for all othe bytes
for (bI = 0; bI < bLen - 2; bI++)
{
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// set i2c address and read
I2CMasterSlaveAddrSet(I2C0_BASE, bAdd, true);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// read on the bus
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// check fault
if (I2CMasterErr(I2C0_BASE) != I2C_MASTER_ERR_NONE)
{
eFault = SYS_RESLT__I2C; // fault
}
while (I2CMasterBusy(I2C0_BASE))
{
}
// get data
pbBytesRead[bI + 1] = I2CMasterDataGet(I2C0_BASE);
// break if new message
if (pbBytesRead[bI + 1] == 0x24)
{
break;
}
}
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// set i2c address and read
I2CMasterSlaveAddrSet(I2C0_BASE, bAdd, true);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// read on the bus last byte
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
// wait
while (I2CMasterBusy(I2C0_BASE))
{
}
// check fault
if (I2CMasterErr(I2C0_BASE) != I2C_MASTER_ERR_NONE)
{
eFault = SYS_RESLT__I2C; // fault
}
while (I2CMasterBusy(I2C0_BASE))
{
}
// get data
pbBytesRead[bI + 1] = I2CMasterDataGet(I2C0_BASE);
}
return eFault;}
I Use a logic Analyzer to watch the i2c bus an there everything seams fine the message is correct and look like it should be. so I think the Problem is not the slave. the Problem is that in pbBytesRead are most of the bytes tow ore more times. for example the logic analyzer says on the bus was : 0x24 0x42 0x45 0x76 0x64. but the launchepad reads in pbBytesRead : 0x24 0x24 0x24 0x42 0x42 0x45 0x45 0x45 0x76 0x76 0x76 0x64 0x64 0x64. maybe something with the init is wrong? has anybody some clue or hint for me? if needed I can provide some more information.
kind regards

65535 cnt value on TTN network

I'm trying to run Lmic library build for arduino (https://github.com/matthijskooijman/arduino-lmic) to work with my Renesas Synergy SK-S7G2 board using e2 studio.
I have altered the hal.cpp file and now the code runs perfectly and I can see the up-link message on the TTN network, The problem that I am facing is that my frame is somehow changing between aes encryption (my guess) because I have checked it before encryption and it shows the LMIC.frame[6] and
LMIC.frame[7] values to be 0x00 but for some reason what I am receiving on the TTN network is 0xFF. and because of this the cnt on TTN shows 65535 as the first count.
The library has 2 aes methods which can be used and I have tried both but they give me the same result.
The reasons I have come up with so far is:
32 bit arm m4 processor may be the cause, as the library was intended for 8 bit arduino (but library also has a 32bit processor version for aes and I have tried that as well but got same result)
My hal_ticks() function is still not doing what it is supposed to do.
I would love an input from anyone, below you can see the console output on e2 studio and the physical payload received on the TTN network. I am also attaching the hal.c file that I have made.
Thank you in advance
physical payload received on TTN
406511012680 FFFF 0171F9EF1810C3B61F4D4EDE940844A945CE
console messages while running on e2 studio
Starting..
Time: 0
RXMODE_RSSI
5824: engineUpdate, opmode=0x808
7349: TXMODE, freq=868100000, len=26, SF=7, BW=125, CR=4/5, IH=0
Packet queued
42111: RXMODE_SINGLE, freq=868100000, SF=7, BW=125, CR=4/5, IH=0
73505: RXMODE_SINGLE, freq=869525000, SF=9, BW=125, CR=4/5, IH=0
75435Event
EV_TXCOMPLETE (includes waiting for RX windows)
79028: engineUpdate, opmode=0x900
hal.c file
/*
* hal.c
*
* Created on: Jul 4, 2019
* Author: areeb
*/
/*******************************************************************************
* Copyright (c) 2015 Matthijs Kooijman
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This the HAL to run LMIC on top of the Arduino environment.
*******************************************************************************/
#include <hal/hal.h>
#include "hal_data.h"
#include <stdio.h>
#include "../lmic/lmic.h"
ssp_err_t err;
u4_t t ;
unsigned int ticks=0, fg=0;
u2_t cnt=0 ;
uint32_t scaled = 0, ch=0;
static volatile bool spi_done = false;
static bool dio_states[3] = {0};
void spi_callback(spi_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
spi_done= true;
}
void timer0_callback(timer_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
ticks++;
}
void irq_callback(external_irq_callback_args_t *p_args)
{
if(p_args->channel == 1)
{
dio_states[0]=1;
radio_irq_handler(0);
dio_states[0]=0;
}
else if(p_args->channel == 2)
{
dio_states[1]=1;
radio_irq_handler(1);
dio_states[0]=0;
}
else if(p_args->channel == 14)
{
dio_states[2]=1;
radio_irq_handler(2);
}
else
{
;
}
// if(p_args->channel == 14)
// {
// radio_irq_handler(2);
// }
}
// -----------------------------------------------------------------------------
// I/O
//#define nss (IOPORT_PORT_04_PIN_13)
//
//#define rst (IOPORT_PORT_05_PIN_11)
u1_t transmit[1]={0},ccc=0;
u1_t recv[1]={0};
static void hal_io_init () {
// g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT);
}
// val == 1 => tx 1
void hal_pin_rxtx (u1_t val) {
}
// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
g_ioport.p_api->init(g_ioport.p_cfg);
if(val == 0 || val == 1)
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_LOW);
else if (val == 1)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_HIGH);
}
else
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
}
}
ioport_level_t readpin;
u1_t rd=0;
//static void hal_io_check() {
//
// uint8_t i;
// for (i = 0; i < NUM_DIO; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
// g_ioport.p_api->pinRead(lmic_pins.dio[i], &readpin);
// if(readpin == IOPORT_LEVEL_HIGH)
// rd = 1;
// else
// rd = 0;
//
// if (dio_states[i] != readpin) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
//
//
//}
void hal_io_check() {
uint8_t i;
// for (i = 0; i < 3; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
//
// if (dio_states[i] != 0) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
// radio_irq_handler(0);
}
// -----------------------------------------------------------------------------
// SPI
//static const SPISettings settings(10E6, MSBFIRST, SPI_MODE0);
static void hal_spi_init () {
err = g_spi0.p_api->open(g_spi0.p_ctrl,g_spi0.p_cfg);
err = g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
err = g_timer0.p_api->start(g_timer0.p_ctrl);
g_external_irq0.p_api->open(g_external_irq0.p_ctrl,g_external_irq0.p_cfg);
g_external_irq0.p_api->enable(g_external_irq0.p_ctrl);
g_external_irq0.p_api->triggerSet(g_external_irq0.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq1.p_api->open(g_external_irq1.p_ctrl,g_external_irq1.p_cfg);
g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
g_external_irq1.p_api->triggerSet(g_external_irq1.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq2.p_api->open(g_external_irq2.p_ctrl,g_external_irq2.p_cfg);
g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
g_external_irq2.p_api->triggerSet(g_external_irq2.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
}
void hal_pin_nss (u1_t val) {
g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_LOW);
else if(val == 1)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_HIGH);
}
// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
if((out & 0x80) == 0x80)
{
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return 0;
}
else if((out > 0x00) && (out & 0x80) != 0x80)
{
ccc = out;
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
}
else if(out == 0x00)
{
g_spi0.p_api->read(g_spi0.p_ctrl, recv, sizeof(recv), SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return recv[0];
}
return recv[0];
}
// -----------------------------------------------------------------------------
// TIME
static void hal_time_init () {
// Nothing to do
}
u4_t hal_ticks () {
// Because micros() is scaled down in this function, micros() will
// overflow before the tick timer should, causing the tick timer to
// miss a significant part of its values if not corrected. To fix
// this, the "overflow" serves as an overflow area for the micros()
// counter. It consists of three parts:
// - The US_PER_OSTICK upper bits are effectively an extension for
// the micros() counter and are added to the result of this
// function.
// - The next bit overlaps with the most significant bit of
// micros(). This is used to detect micros() overflows.
// - The remaining bits are always zero.
//
// By comparing the overlapping bit with the corresponding bit in
// the micros() return value, overflows can be detected and the
// upper bits are incremented. This is done using some clever
// bitwise operations, to remove the need for comparisons and a
// jumps, which should result in efficient code. By avoiding shifts
// other than by multiples of 8 as much as possible, this is also
// efficient on AVR (which only has 1-bit shifts).
// g_timer0.p_api->stop(g_timer0.p_ctrl);
// static uint8_t overflow = 0;
// Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
// the others will be the lower bits of our return value.
// u4_t t = ticks;
// g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
// cnt = 65535-cnt;
// if( (cnt > 65000) && (cnt < 65535 ) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// scaled = ticks >> US_PER_OSTICK_EXPONENT; // 625
// Most significant byte of scaled
// uint8_t msb = scaled >> 24;
// Mask pointing to the overlapping bit in msb and overflow.
// const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
// Update overflow. If the overlapping bit is different
// between overflow and msb, it is added to the stored value,
// so the overlapping bit becomes equal again and, if it changed
// from 1 to 0, the upper bits are incremented.
// overflow += (msb ^ overflow) & mask;
// Return the scaled value with the upper bits of stored added. The
// overlapping bit will be equal and the lower bits will be 0, so
// bitwise or is a no-op for them.
// g_timer0.p_api->start(g_timer0.p_ctrl);
// return scaled | ((uint32_t)overflow << 24);
// 0 leads to correct, but overly complex code (it could just return
// micros() unmodified), 8 leaves no room for the overlapping bit.
// static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
t = ticks;
//
//// hal_disableIRQs();
///
g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
if(cnt != 0 )
cnt = 65535 - cnt;
// if( (cnt < 500) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// hal_enableIRQs();
return ((t<<16)|cnt);
}
// Returns the number of ticks until time. Negative values indicate that
// time has already passed.
static s4_t delta_time(u4_t time) {
u4_t t = hal_ticks();
s4_t d = time - t;
if( d<=0 ) return 0; // in the past
if( (d>>16)!=0 ) return 0xFFFF; // far ahead
return (u2_t)d;
}
void hal_waitUntil (u4_t time) {
while( delta_time(time) != 0 );
}
// s4_t delta = delta_time(time);
// // From delayMicroseconds docs: Currently, the largest value that
// // will produce an accurate delay is 16383.
// while (delta > (16000 / US_PER_OSTICK)) {
// R_BSP_SoftwareDelay(16, BSP_DELAY_UNITS_MILLISECONDS);
// delta -= (16000 / US_PER_OSTICK);
// }
// if (delta > 0)
// R_BSP_SoftwareDelay((delta * US_PER_OSTICK), BSP_DELAY_UNITS_MICROSECONDS);
//// delayMicroseconds(delta * US_PER_OSTICK);
//}
// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
// No need to schedule wakeup, since we're not sleeping
return delta_time(time) <= 0;
}
static uint8_t irqlevel = 0;
void hal_disableIRQs () {
// __disable_irq();
// g_timer0.p_api->close(g_timer0.p_ctrl);
// g_external_irq1.p_api->disable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->disable(g_external_irq2.p_ctrl);
irqlevel++;
}
void hal_enableIRQs () {
if(--irqlevel == 0) {
// __enable_irq();
// g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
// g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
// Instead of using proper interrupts (which are a bit tricky
// and/or not available on all pins on AVR), just poll the pin
// values. Since os_runloop disables and re-enables interrupts,
// putting this here makes sure we check at least once every
// loop.
//
// As an additional bonus, this prevents the can of worms that
// we would otherwise get for running SPI transfers inside ISRs
hal_io_check();
}
hal_io_check();
}
void hal_sleep () {
// Not implemented
}
// -----------------------------------------------------------------------------
#if defined(LMIC_PRINTF_TO)
static int uart_putchar (char c, FILE *)
{
LMIC_PRINTF_TO.write(c) ;
return 0 ;
}
void hal_printf_init() {
// create a FILE structure to reference our UART output function
static FILE uartout;
memset(&uartout, 0, sizeof(uartout));
// fill in the UART file descriptor with pointer to writer.
fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
// The uart is the standard output device STDOUT.
stdout = &uartout ;
}
#endif // defined(LMIC_PRINTF_TO)
void hal_init () {
// configure radio I/O and interrupt handler
hal_io_init();
// configure radio SPI
hal_spi_init();
// configure timer and interrupt handler
hal_time_init();
#if defined(LMIC_PRINTF_TO)
// printf support
hal_printf_init();
#endif
}
void hal_failed (const char *file, u2_t line) {
}

Why "HAL_I2C_Master_Transmit" writes 2 bytes of data in each loop

I'm using HAL library for stm32f4 (V1.7.1) and trying to understand how HAL_I2C_Master_Transmit works. This function transmits a "master to slave" packet on SDA line.
In the stm32f4xx_hal_i2c.c code after sending slave address there is a loop (while(hi2c->XferSize > 0U)) that sends bytes which we want to be transmitted to slave. This loop works until all bytes are transmitted. But there is a question that "why the function wants to transmit TWO bytes in each loop?" There is an IF in loop (if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U))) that checks if the previous byte is currently transferred then send the the next byte!
I don't know what is the reason of existing this IF when in the next loop other bytes can be transmitted?!
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t
DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
uint32_t tickstart = 0x00U;
/* Init tickstart for timeout management*/
tickstart = HAL_GetTick();
if(hi2c->State == HAL_I2C_STATE_READY)
{
/* Wait until BUSY flag is reset */
if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET,
I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK)
{
return HAL_BUSY;
}
/* Process Locked */
__HAL_LOCK(hi2c);
/* Check if the I2C is already enabled */
if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
{
/* Enable I2C peripheral */
__HAL_I2C_ENABLE(hi2c);
}
/* Disable Pos */
hi2c->Instance->CR1 &= ~I2C_CR1_POS;
hi2c->State = HAL_I2C_STATE_BUSY_TX;
hi2c->Mode = HAL_I2C_MODE_MASTER;
hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
/* Prepare transfer parameters */
hi2c->pBuffPtr = pData;
hi2c->XferCount = Size;
hi2c->XferOptions = I2C_NO_OPTION_FRAME;
hi2c->XferSize = hi2c->XferCount;
/* Send Slave Address */
if(I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) != HAL_OK)
{
if(hi2c->ErrorCode == HAL_I2C_ERROR_AF)
{
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
return HAL_ERROR;
}
else
{
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
return HAL_TIMEOUT;
}
}
/* Clear ADDR flag */
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
while(hi2c->XferSize > 0U)
{
/* Wait until TXE flag is set */
if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
{
if(hi2c->ErrorCode == HAL_I2C_ERROR_AF)
{
/* Generate Stop */
hi2c->Instance->CR1 |= I2C_CR1_STOP;
return HAL_ERROR;
}
else
{
return HAL_TIMEOUT;
}
}
/* Write data to DR */
hi2c->Instance->DR = (*hi2c->pBuffPtr++);
hi2c->XferCount--;
hi2c->XferSize--;
if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U))
{
/* Write data to DR */
hi2c->Instance->DR = (*hi2c->pBuffPtr++);
hi2c->XferCount--;
hi2c->XferSize--;
}
/* Wait until BTF flag is set */
if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
{
if(hi2c->ErrorCode == HAL_I2C_ERROR_AF)
{
/* Generate Stop */
hi2c->Instance->CR1 |= I2C_CR1_STOP;
return HAL_ERROR;
}
else
{
return HAL_TIMEOUT;
}
}
}
/* Generate Stop */
hi2c->Instance->CR1 |= I2C_CR1_STOP;
hi2c->State = HAL_I2C_STATE_READY;
hi2c->Mode = HAL_I2C_MODE_NONE;
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}

Sockets using GetQueuedCompletionStatus and ERROR_MORE_DATA

I am trying to use GetQueuedCompletionStatus with winsocks, but I can't seem to get it right. The procedure is as follows:
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0,
NULL, 0, WSA_FLAG_OVERLAPPED);
....
bind(sck,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
HANDLE hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
OVERLAPPED pOverlapped = {0,};
WSARecvFrom(sck,NULL,0,NULL,NULL,(struct sockaddr *)&laddr,&lsize,&pOverlapped,0);
BOOL bReturn = GetQueuedCompletionStatus(
hPort,
&rbytes,
(LPDWORD)&lpContext,
&pOutOverlapped,
INFINITE);
...
}
I then send some network data to the bound port from an external tool. GetQueuedCompletionStatus returns FALSE, and GetLastError() returns ERROR_MORE_DATA, which sounds correct, since I hadn't provided a buffer in WSARecvFrom.
The question is how can I provide a buffer to actually get the data from the failed I/O operation?
I tried to issue a WSARecvFrom with the original overlapped structured, but it simply queues another read, and a subsequent call to GetQueuedCompletionStatus does not return until more network data is sent.
Calling WSARecvFrom without an overlapped structure blocks it, and it also doesn't return until more network data is sent.
So, how can I handle ERROR_MORE_DATA properly, without losing the data from the first operation?
You must provide a buffer to WSARecvFrom(), just like with any read operation regardless of whether you use IOCP or not. You must ensure the buffer stays valid in memory until the IOCP operation is complete. IOCP fills the buffer you provide and then notifies the completion port when finished.
UDP cannot transfer more than 65535 bytes in a single datagram, so you can use that as your max buffer size.
In your example, your code is written to run synchronously (defeating the purpose of using IOCP at all), so you can use a local buffer:
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sck == INVALID_SOCKET)
{
// error, do something...
return;
}
....
bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
HANDLE hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
if (!hPort)
{
// error, do something...
return;
}
WSAOVERLAPPED Overlapped = {0};
Overlapped.hEvent = WSACreateEvent();
BYTE buffer[0xFFFF];
DWORD dwBytesRecvd = 0;
DWORD dwFlags = 0;
sockaddr_in fromaddr = {0};
int fromaddrlen = sizeof(fromaddr);
WSABUF buf;
buf.len = sizeof(buffer);
buf.buf = buffer;
int iRet = WSARecvFrom(sck, &buf, 1, &dwBytesRecvd, &dwFlags, (sockaddr*)&fromaddr, &fromaddrlen, &Overlapped, NULL);
if (iRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// error, do something...
return;
}
DWORD rBytes;
ULONG_PTR key;
LPOVERLAPPED pOverlapped = NULL;
if (!GetQueuedCompletionStatus(hPort, &rbytes, &key, &pOverlapped, INFINITE))
{
if (pOverlapped)
{
// WSARecvFrom() failed...
}
else
{
// GetQueuedCompletionStatus() failed...
}
// do something...
return;
}
}
// I/O complete, use buffer, dwBytesRecvd, dwFlags, and fromaddr as needed...
}
However, this defeats the purpose of IOCP. If you really want to be synchronous, you could just use recvfrom() instead and let it block the calling thread until data arrives. IOCP works best when you have a pool of threads servicing the completion port. Call WSARecvFrom() and let it work in the background, don't wait on it. Let a separate thread call GetQueuedCompletionPort() and process the data when it is received, eg:
struct MyOverlapped
{
WSAOVERLAPPED overlapped;
BYTE buffer[0xFFFF];
DWORD buflen;
DWORD flags;
sockaddr_storage fromaddr;
int fromaddrLen;
};
HANDLE hPort = NULL;
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sck == INVALID_SOCKET)
{
// error, do something...
return;
}
....
bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
if (!hPort)
{
// error, do something...
return;
}
MyOverlapped *ov = new MyOverlapped;
ZeroMemory(ov, sizeof(*ov));
ov->overlapped.hEvent = WSACreateEvent();
ov->fromaddrlen = sizeof(ov->fromaddr);
WSABUF buf;
buf.len = sizeof(ov->buffer);
buf.buf = ov->buffer;
int iRet = WSARecvFrom(sck, &buf, 1, &ov->buflen, &ov->flags, (sockaddr*)&ov->fromaddr, &ov->fromaddrlen, (WSAOVERLAPPED*)ov, NULL);
if (iRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// error, do something...
return;
}
// WSARecvFrom() is now operating in the background,
// the IOCP port will be signaled when finished...
}
else
{
// data is already available,
// the IOCP port will be signaled immediately...
}
...
}
...
// in another thread...
{
...
DWORD rbytes;
ULONG_PTR key;
MyOverlapped *ov = NULL;
if (!GetQueuedCompletionStatus(hPort, &rbytes, &key, (LPOVERLAPPED*)&ov, INFINITE))
{
if (ov)
{
// WSARecvFrom() failed...
// free ov, or reuse it for another operation...
}
else
{
// GetQueuedCompletionStatus() failed...
}
}
else
{
// use ov as needed...
// free ov, or reuse it for another operation...
}
...
}

Get Xbee response from Serial and send to a browser

I am trying to do some experiments with Arduino, Ethernet Shield and Xbee Shield.
I demonstrate my set up board like this:
Group 1: Arduino Uno + Xbee shield : broadcast the signal
Group 2: Arduino Uno + Xbee shield + Ethernet shield: receive the signal from
group 1, get the signal strength from AT command and print it into the browser.
The problem here is I can't get the result after sending to the Serial my ATDB command, actually, I am not sure it did worked as I expected.
Here is the code that I used to retrieve the signal strength.
int data;
void setup()
{
Serial.begin(9600);
}
void receiver_checker(){
delay(1200);
Serial.print("+++");
delay(1200);
bool bOK = false;
while (Serial.available() > 0) {
Serial.write(Serial.read());
bOK = true;
}
if(bOK)
{
Serial.println();
Serial.println("ATDB");
delay(100);
while (Serial.available() > 0) {
Serial.write(Serial.read());
}
Serial.println();
}
Serial.println();
}
void loop()
{
while(Serial.available() > 0){
data = Serial.read();
if(data == '1'){
// Broadcaster 1
//Serial.println("1------------------");
receiver_checker();
}
}
}
This part worked as I expected, it printed out in hex number the signal strength of the last package that it received.
Here is the code I combined the previous one and the server part from Web Server tutorial:
#include <SPI.h>
#include <Ethernet.h>
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xCA, 0xFE, 0x00, 0x00, 0x00, 0x02
};
IPAddress ip(1, 1, 1, 2);
int data;
int count = 0;
char result;
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
// Serial.print("server is at ");
// Serial.println(Ethernet.localIP());
}
void loop() {
// listen for incoming clients
EthernetClient client = server.available();
if (client) {
// Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
data = Serial.read();
// if it's a capital H (ASCII 72), turn on the LED:
if (data == '1') {
count += 1;
client.print("The number of times:");
client.print(count);
result = receiver_checker();
client.print("========================");
client.print(result);
client.print("========================");
}
}
client.println("</html>");
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(1);
// close the connection:
client.stop();
Serial.println("client disconnected");
}
}
char receiver_checker(){
char signal;
delay(1200);
Serial.print("+++");
delay(1200);
bool bOK = false;
while (Serial.available() > 0) {
Serial.write(Serial.read());
bOK = true;
}
if(bOK)
{
Serial.println();
Serial.println("ATDB");
delay(100);
while (Serial.available() > 0) {
signal = Serial.read();
}
Serial.println();
}
Serial.println();
return signal;
}
If there is another way to interact with the Xbee shield not go through Serial like I ask and get response directly, please let me know!
Your receiver_checker() function is reading characters back from the XBee module, and just returning the last character received, which is likely a carriage return or line feed.
Update the function to return an int, and replace your while (Serial.available() > 0) with the following:
signal = (int) strtoul(Serial.readString().c_str(), 0, 16);
That's for when the XBee returns a hexadecimal value. If it's returning a decimal value, change the 16 parameter to a 10.