Related
I am trying to find an answer where I could able to read the flow control for request message using CAPL program for SID 2E UDS Diagnostic. I have implemented ISOTP protocol on server side for transmitting multi frame response message which is working fine.
I have added below CAPL program for your reference. Now my problem is I want to write a CAPL program which works like a client request message. I have added few keys to trigger the request msg. As I am not able to receive flow control FC and CF consecutive frame while requesting the message. I don't have a CDD file to config in the diganostics panel.
Please could someone help me to fix this issue. At least an example would be really appreciated.
/*#!Encoding:1252*/
includes
{
}
variables
{
//Golbal variables declaration
msTimer timer_DIAG;
byte checkByte0;
message 0x713 msg = { dlc=8}; //0x713 request msg Need help to fix when SID 2E is requested
byte check_byte0;
message 0x71B sendmsg; //0x71B response msg
}
//Request message from client to server 0x713 CAN ID
on message 0x713
{
// tester_DiagReqEds = this.tester_DiagReqEds;
// write(" Request CAN msg 0x723 Received %x", tester_DiagReqEds);
checkByte0 = this.byte(0) & 0x30;
if(checkByte0 == 0x30) //FC frame
{
msg.dlc = 8;
msg.dword(0) = 0x30;
msg.dword(4) = 0x00;
output(msg);
}
}
//send request write data by identifier 2E F190 parameters
on key 'q'
{
msg.byte(0) = 0x09;
msg.byte(1) = 0x2E;
msg.byte(2) = 0xF1;
msg.byte(3) = 0x90;
msg.byte(4) = 0x10;
msg.byte(5) = 0x20;
msg.byte(6) = 0x30;
msg.byte(7) = 0x40;
msg.byte(8) = 0x01;
msg.byte(9) = 0x02;
msg.byte(10) = 0x03;
output(msg);
}
//send request read data by identifier 22 F190 parameters below 8 bytes which is working fine
on key 'e'
{
msg.byte(0) = 0x03;
msg.byte(1) = 0x2E;
msg.byte(2) = 0xF1;
msg.byte(3) = 0x90;
msg.byte(4) = 0x10;
msg.byte(5) = 0x20;
msg.byte(6) = 0x00;
msg.byte(7) = 0x00;
output(msg);
}
//send request to read data by identifier 22 F190 parameters working fine
on key 'w'
{
msg.byte(0) = 0x03;
msg.byte(1) = 0x22;
msg.byte(2) = 0xF1;
msg.byte(3) = 0x90;
msg.byte(4) = 0x00;
msg.byte(5) = 0x00;
msg.byte(6) = 0x00;
msg.byte(7) = 0x00;
output(msg);
}
//response message for flow control frame
on message 0x71B
{
// checkByte0 = this.byte(0) & 0x30;
//
// if(checkByte0 == 0x10)
// {
// sendmsg.dword(0) = 0x30;
// sendmsg.dword(4) = 0x00;
// output(sendmsg);
// }
}
You want to send the payload
2E F1 90 10 20 30 40 50 60 70
using ISO TP.
In order to do so, you have to follow the ISO-TP specification and segment the data into one first frame and (possibly several) consecutive frames. The consecutive frames should only be sent after you have received a flow control frame.
These frames should look like:
First frame: 10 0A 2E F1 90 10 20 30
Consecutive frame: 21 40 50 60 70 00 00 00
Explanation:
10 0A 2E F1 90 10 20 30:
1 in the first nibble means, this is a first frame
0 0A the next three nibbles contain the length of the payload. You want to send 10 bytes, hence 0x00A bytes
After that the first frame contains the first 6 bytes of your payload.
21 40 50 60 70 00 00 00:
2 in the first nibble means, this is a consecutive frame
1 in the second nibble means, that this is the first consecutive frame, the second would have a 2 here and so on.
After that there are the next 7 bytes of your payload.
In CAPL code this would look like:
on key 'q'
{
msg.byte(0) = 0x10;
msg.byte(1) = 0x0A
msg.byte(2) = 0x2E;
msg.byte(3) = 0xF1;
msg.byte(4) = 0x90;
msg.byte(5) = 0x10;
msg.byte(6) = 0x20;
msg.byte(7) = 0x30;
output(msg);
}
on message 0x713
{
checkByte0 = this.byte(0) & 0x30;
if(checkByte0 == 0x30) //FC frame
{
msg.byte(0) = 0x21;
msg.byte(1) = 0x40;
msg.byte(2) = 0x50;
msg.byte(3) = 0x60;
msg.byte(4) = 0x70;
output(msg);
}
}
So what you have to do is:
Send the first frame, wait for the flow control frame, send the consecutive frame.
Again, there is no need to do this manually. CANoe comes with an implementation of CanTp. IIRC, there is a demo configuration coming with CANoe called "CanTp" or "IsoTp". There is no need to use a CDD.
By the way, there is no difference between "client" and "server" in ISOTP. When you have a working implementation on server side, you can simply use the same logic on client side.
#M.Spiller, thank you for explaining in detail. I have tried as you explained but I am confused when receiving the bytes from CAN request followed by capl code. Below I am adding code where I receive the request from CANOe. I want to know, do I missed something that I need to add a code to server to read request from CANOe. Currently, CANOe is not sending multiframe since it is looking response message from server (FC) I assume. Please could tell me where could be the issue ?
/* just for underestanding Where
#define ISOTP_SF 0x00 /* single frame */
#define ISOTP_FF 0x10 /* first frame */
#define ISOTP_CF 0x20 /* consecutive frame */
#define ISOTP_FC 0x30 /* flow control */
CanData[8] = {0,0,0,0,0,0,0,0}
for(dtcnt=0; dtcnt<RxCAN->DLC; dtcnt++)
{
CanData[dtcnt]= RxCAN->Data[dtcnt];
}*/
switch((uint16_t)RxCAN->StdId){
case TESTER_FUNC: //CAN 0x713 Rq
{
/*Request message from CAN to Diagnostic*/
/*If Isotp Single frame == 0 then read 8 byte data */
dgiIsoTp.IsoTpFrameTypeRcv = (0xF0 & CanData[0]);
if (dgiIsoTp.IsoTpFrameTypeRcv == ISOTP_SF)
{
//Function to read CAN request message flow control
ReadCanMsgfrom_Tester(CanData, TESTER_FUNC);
}
else if(dgiIsoTp.IsoTpFrameTypeRcv == ISOTP_FF)
{
if (TimeOutTickFFtoFC_Enable == 1)
{
TimeOutTickFFtoFC_Enable = 0;
dgiIsoTp.IsoTpFC = 0x0F & CanData[0];
dgiIsoTp.IsoTpBlocksize = CanData[1];
dgiIsoTp.IsoTpST = CanData[2];
dgiIsoTp.IsoTpCfFlag = TP_N_WAIT;
CF_Tick = dgiIsoTp.IsoTpST >> 0x01;
CF_TickEnable = 1;
}
}
break;
}
}
Please need your support me to get an idea. enter image description here
#M.Spiller, thank you so much for responding. I made changes in my code as you explained I forgot to update the 1st byte 0x10 FF. . From the above CAPL code I have added few more line to test and partially it is working.
Initially I have length 17 bytes for write 2E F190. I am writing 7 bytes into memory. I want to read bytes which I have written in memory.
But when I request 22 F190 (I have set max length 17 bytes) where I get don'T receive all the7 bytes which I have written. Please could you notice where the mistake would be ?
on message 0x713
{
checkByte0 = this.byte(0) & 0x30;
write("checkbyte value %x",checkByte0 );
if(checkByte0 == 0x30) //FC frame
{
msg.byte(0) = 0x21;
msg.byte(1) = 0x40;
msg.byte(2) = 0x50;
msg.byte(3) = 0x60;
msg.byte(4) = 0x70;
output(msg);
}
else if(checkByte0 == 0x10) //FC frame
{
msg.byte(0) = 0x21;
msg.byte(1) = 0x40;
msg.byte(2) = 0x50;
msg.byte(3) = 0x60;
msg.byte(4) = 0x70;
output(msg);
}
}
//send request write data by identifier 2E F190 parameters
on key 'q'
{
msg.byte(0) = 0x10;
msg.byte(1) = 0x0A;
msg.byte(2) = 0x2E;
msg.byte(3) = 0xF1;
msg.byte(4) = 0x90;
msg.byte(5) = 0x10;
msg.byte(6) = 0x20;
msg.byte(7) = 0x30;
output(msg);
}
In the pitcure you can notice I am able to send multi frame the code is able to receive now.Please let me know if
enter image description here
You want to send the payload
2E F1 90 10 20 30 40 50 60 70
using ISO TP.
In order to do so, you have to follow the ISO-TP specification and segment the data into one first frame and (possibly several) consecutive frames. The consecutive frames should only be sent after you have received a flow control frame.
These frames should look like:
First frame: 10 0A 2E F1 90 10 20 30
Consecutive frame: 21 40 50 60 70 00 00 00
Explanation:
10 0A 2E F1 90 10 20 30:
1 in the first nibble means, this is a first frame
0 0A the next three nibbles contain the length of the payload. You want to send 10 bytes, hence 0x00A bytes
After that the first frame contains the first 6 bytes of your payload.
21 40 50 60 70 00 00 00:
2 in the first nibble means, this is a consecutive frame
1 in the second nibble means, that this is the first consecutive frame, the second would have a 2 here and so on.
After that there are the next 7 bytes of your payload.
In CAPL code this would look like:
on key 'q'
{
msg.byte(0) = 0x10;
msg.byte(1) = 0x0A
msg.byte(2) = 0x2E;
msg.byte(3) = 0xF1;
msg.byte(4) = 0x90;
msg.byte(5) = 0x10;
msg.byte(6) = 0x20;
msg.byte(7) = 0x30;
output(msg);
}
on message 0x713
{
checkByte0 = this.byte(0) & 0x30;
if(checkByte0 == 0x30) //FC frame
{
msg.byte(0) = 0x21;
msg.byte(1) = 0x40;
msg.byte(2) = 0x50;
msg.byte(3) = 0x60;
msg.byte(4) = 0x70;
output(msg);
}
}
So what you have to do is:
Send the first frame, wait for the flow control frame, send the consecutive frame.
Again, there is no need to do this manually. CANoe comes with an implementation of CanTp. IIRC, there is a demo configuration coming with CANoe called "CanTp" or "IsoTp". There is no need to use a CDD.
By the way, there is no difference between "client" and "server" in ISOTP. When you have a working implementation on server side, you can simply use the same logic on client side.
I know there is #use rs232 command to activate it,
but i want to know how to set registers individually to activate rs232
i'm using PIC18f13k22.
I did like this:
INTCON = 0xc2;
IPR1 = 0x7f;
PIE1 = 0x20;
PIR1 = 0x10;
BAUDCON = 0x48;
RCSTA = 0x90;
TXSTA = 0xA6;
SPBRG = 0x82;
SPBRGH = 0x06;
I looked up PIC18f13k22 datasheet, and found related registers, and set like that.
and didn't work.
need help!
thanks
Here is a complete code that builds with Microchip MPLABX and XC8 v2.30:
/*
* File: main.c
* Author: dan1138
* Compiler: XC8 v2.30
*
* Created on October 6, 2020, 1:41 PM
*/
#pragma config FOSC = IRC, PLLEN = OFF, PCLKEN = ON, FCMEN = OFF, IESO = OFF
#pragma config PWRTEN = OFF, BOREN = SBORDIS, BORV = 19, WDTEN = OFF
#pragma config WDTPS = 32768, HFOFST = ON, MCLRE = ON, STVREN = ON, LVP = OFF
#pragma config BBSIZ = OFF, XINST = OFF, DEBUG = OFF, CP0 = OFF, CP1 = OFF
#pragma config CPB = OFF, CPD = OFF, WRT0 = OFF, WRT1 = OFF, WRTC = OFF
#pragma config WRTB = OFF, WRTD = OFF, EBTR0 = OFF, EBTR1 = OFF, EBTRB = OFF
#include <xc.h>
#include <stdio.h>
void putch(char txData)
{
if(1 == RCSTAbits.OERR)
{
RCSTAbits.CREN = 0;
RCSTAbits.CREN = 1;
}
while(0 == PIR1bits.TXIF)
{
}
TXREG = txData;
}
void main(void)
{
OSCCON = 0x60;
OSCCON2 = 0x04;
OSCTUNE = 0x00;
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
TRISA = 0x37;
TRISB = 0x70;
TRISC = 0xFF;
ANSEL = 0xFF;
ANSELH = 0x07;
WPUB = 0x00;
WPUA = 0x00;
INTCON2bits.nRBPU = 1;
BAUDCON = 0x08;
RCSTA = 0x90;
TXSTA = 0x24;
SPBRG = 0xCF;
SPBRGH = 0x00;
PIR1bits.TXIF = 0;
printf("\r\nPIC18F13K22 UART demo\r\n");
while (1)
{
}
}
The solution to your problem lies in knowing what to set the configuration word values to, and how to comprehend what information can be found in the data sheet.
I know the data sheet is dense and only documents what can be selected, but not why specific values should be chosen.
With more experience you can learn how to read data sheets and what can be useful.
As you made no effort to comment in the code you posted my code is likewise missing anything close to a useful comment.
I'm trying to set up my STM32F407-Discovery board to read multiple ADC channels from ADC1 using the DMA controller. I can easily read the analog value one at a time without using DMA, but as soon as I enable DMA for the ADC, ADC1->DR is always 0, and adc_vals is filled with zeros. Furthermore, it hangs on while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));.
EDIT: it would appear DMA_GetCmdStatus is returning DISABLED. Any ideas?
Is there a way to start the ADC or something that I'm missing?
//setup adc1: in1,2,3,8,9,15
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //adc1 on the apb2 peripheral bus
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right;
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE;
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = NUM_ADC;
adc.ADC_ScanConvMode = ENABLE;
ADC_Init(ADC1,&adc);
ADC_DMACmd(ADC1, ENABLE); //enable adc for dma. When this line is removed, I see data on ADC1->DR
ADC_Cmd(ADC1,ENABLE);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_144Cycles);//1:1710, 0
//ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_144Cycles);//2:1710, 0
//ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_144Cycles);//3:1710, 0
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_144Cycles);//8:3520
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_144Cycles);//9:1000
//ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_144Cycles);//15:3920
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); //dma1 clock enable
DMA_InitTypeDef dma;
DMA_DeInit(DMA2_Stream0); //reset DMA2 stream 0 to default values
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_Memory0BaseAddr = (uint32_t)&adc_vals[0];
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = NUM_ADC;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT, ENABLE); //Enable DMA Stream Half / Transfer Complete interrupt
DMA_Cmd(DMA2_Stream0, ENABLE); //DMA2_Stream0 enable
//dma transfer complete interrupt:
NVIC_InitTypeDef nvic;
//Enable DMA1 channel IRQ Channel
nvic.NVIC_IRQChannel = DMA2_Stream0_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
ADC_SoftwareStartConv(ADC1);//Start the adc conversion
At least you can try:
change DMA_PeripheralInc to enable
use ADC_DMARequestAfterLastTransferCmd(ADC, Enable); for dma request after group conversion.
init ADC_CommonInitTypeDef
init GPIO, if not
Moreover enabling ADC before all the configurations is strange.
In my opinion the best way is to copy-paste "ADC_DualModeRegulSimu"example from standard peripherals library. It contains beautiful code exactly for your purpose.
There were a number of errors. Here's my working code for anybody else having the same trouble:
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1 on APB2 peripheral bus
DMA_InitTypeDef dma; //dma2/stream0/channel0
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_Memory0BaseAddr = (uint32_t)&adcVal;
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 6;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_Cmd(DMA2_Stream0, ENABLE); //dMA2_Stream0 enable
//analog inputs: PA1,2,3, PC5, PB0,1
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &gpio);
//ADC common init
ADC_CommonInitTypeDef adcCommon;
adcCommon.ADC_Mode = ADC_Mode_Independent;
adcCommon.ADC_Prescaler = ADC_Prescaler_Div2;
adcCommon.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
adcCommon.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&adcCommon);
//setup adc1: in1,2,3,8,9,15
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right; //mask 0b 00001111 11111111
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE; //continuous: constantly converting data - can always read register
adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//external trigger conversion (?)
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = 6;
adc.ADC_ScanConvMode = ENABLE;//single/multichannel
ADC_Init(ADC1,&adc);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_56Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); //single adc repeated
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
Thanks for the code ethan, made minor mod to fit my case and to work as a general function.
volatile uint16_t adcVal[6];
void Setup_DMA_ADC( void )
{
GPIO_InitTypeDef gpio;
//DMA for multiple adc channels:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //ADC1 on APB2 peripheral bus
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
DMA_InitTypeDef dma; //dma2/stream0/channel0
dma.DMA_Channel = DMA_Channel_0;
dma.DMA_Memory0BaseAddr = (uint32_t) &adcVal[0];
dma.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
dma.DMA_BufferSize = 6;
dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma.DMA_Mode = DMA_Mode_Circular;
dma.DMA_Priority = DMA_Priority_High;
dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
dma.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0, &dma);
DMA_Cmd(DMA2_Stream0, ENABLE); //dMA2_Stream0 enable
//analog inputs: PA1,2,3, PC5, PB0,1
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOC, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &gpio);
//ADC common init
ADC_CommonInitTypeDef adcCommon;
adcCommon.ADC_Mode = ADC_Mode_Independent;
adcCommon.ADC_Prescaler = ADC_Prescaler_Div2;
adcCommon.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
adcCommon.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&adcCommon);
//setup adc1: in1,2,3,8,9,15
ADC_InitTypeDef adc;
ADC_DeInit(); //set adc to default state
adc.ADC_DataAlign = ADC_DataAlign_Right; //mask 0b 00001111 11111111
adc.ADC_Resolution = ADC_Resolution_12b;//12 bit = 4096
adc.ADC_ContinuousConvMode = ENABLE; //continuous: constantly converting data - can always read register
adc.ADC_ExternalTrigConv = DISABLE;//ADC_ExternalTrigConv_T1_CC1;//external trigger conversion (?)
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_NbrOfConversion = 6;
adc.ADC_ScanConvMode = ENABLE;//single/multichannel
ADC_Init(ADC1,&adc);
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,2,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,4,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_9,5,ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_15,6,ADC_SampleTime_56Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); //single adc repeated
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1,ENABLE);
// Start ADC conversion
ADC_SoftwareStartConv(ADC1);
return;
}
I'm using non-OS SDK v2.0 for esp8266.
I join a multicast group.
I then receive a message (that was sent to multicast).
I want to respond to the sender, but in struct espconn, udp.remote_ip is the address of the multicast group, not sender.
How do I get the ip address of the sender?
Edit:
Receive function has an void* arg argument that is casted to struct espconn.
The old method doesn't do the job anymore, but I found a way to find remote ip and port.
New code:
struct espconn* udp_ch;
remot_info *premot = NULL;
udp_ch = arg;
if (espconn_get_connection_info(udp_ch,&premot,0) == ESPCONN_OK){
os_printf("%d.%d.%d.%d:%d\n", premot->remote_ip[0], premot->remote_ip[1], premot->remote_ip[2], premot->remote_ip[3], premot->remote_port);
}
else{
os_printf("Get info fail\n");
}
This is exactly what I was searching for before. For now, as far as I can see, it works well.
OLD:
I found a way to find the ip, but I don't think it should be done this way. Until I find better, I will use this.
The first thing I did was print first 256 hex values, from void* arg.
I noticed that my address was occurring before a bunch of zeros.
On unicast, the starting position of 0s was 128.
I'm currently using this function:
uint32_t udp_get_addr(void* arg){
uint32_t adr = 0;
uint16_t pos;
uint8_t* data = (uint8_t*) arg;
//unicast?
for(pos = 128; pos<144; pos++){
if(data[pos] != 0){
adr = 1;
break;
}
}
//multicast
if(adr == 1)
pos = 172;
else
pos = 124;
adr = data[pos]<<24 | data[pos+1]<<16 | data[pos+2]<<8 | data[pos+3];
return adr;
}
I know this method is bad, and there is a number of things that can be changed for the better, but for now, this will do.
Edit2:
I needed the source port also. It is located 4 bytes before address. New functions that I currently use:
#define SRC_ADDR_U 120
#define SRC_ADDR_M 168
uint32_t udp_src_addr(void* arg, uint8_t isMulticast){
uint32_t res;
uint8_t* tmp = (uint8_t*) arg;
uint16_t pos;
if(isMulticast) pos = SRC_ADDR_M+4;
else pos = SRC_ADDR_U+4;
res = (tmp[pos+3] << 24) | (tmp[pos+2] << 16) | (tmp[pos+1] << 8) | tmp[pos];
return res;
}
uint16_t udp_src_port(void* arg, uint8_t isMulticast){
uint32_t res;
uint8_t* tmp = (uint8_t*) arg;
uint16_t pos;
if(isMulticast) pos = SRC_ADDR_M;
else pos = SRC_ADDR_U;
res = (tmp[pos+1] << 8) | tmp[pos];
return res;
}
I doing a project with Arduino Uno R3 and XBee S2 transmission. I use a couple of sensors like a wireless (RF) temperature sensor, two SHT75 sensors, a 3-axis accelerometer and an illumination sensor. And after collecting the data, we use XBee (S2, API mode) to send the data to the gateway. Every round is about one second.
The first problem is the data is about 16 bytes, but the packet does not send successful every round. Sometime it works, and sometimes it doesn't, but the payload of XBee can be 60 or 70 bytes in the datasheet... But if I put the payload as some simply an integer (like 1, 2, 3), not the data from sensor, and the transmission will be stable.
After meeting the problem above, I divided the data into two packets (each with an eight bytes payload), and the first packet is very stable, but the second is very unstable. As mentioned above, if I put some number into the second packets instead of the sensing data the second packet will become stable and send successfully every round.
So I think it's the code problem, but idk where is the problem. I try to change the baud rate or increasing the delay time between the two packets. Where is the problem? The following is my code:
#include <XBee.h>
#include <i2cmaster.h>
#include <string.h>
#include <ctype.h>
#include <Sensirion.h>
#include "Wire.h"
#include "MMA845XQ.h"
**///////////////////////////// XBee setup //////////////////////////////////**
XBee xbee = XBee();
XBeeAddress64 remoteAddress = XBeeAddress64(0x00000000, 0x00000000);
ZBRxResponse zbRx = ZBRxResponse();
ZBTxStatusResponse zbTxStus = ZBTxStatusResponse();
uint8_t payload[] = {0,0,0,0,0,0,0,0,0};
uint8_t payload1[] = {0,0,0,0,0,0,0,0,0};
**///////////////////////////// Accelerometer //////////////////////////////////**
MMA845XQ accel;
**////////////////////////// SHT1 serial data and clock ////////////////////**
const byte dataPin = 2;
const byte sclkPin = 3;
Sensirion sht = Sensirion(dataPin, sclkPin);
unsigned int rawData;
float temperature;
float humidity;
byte stat;
**////////////////////////// SHT2 serial data and clock ////////////////////**
const byte dataPin1 = 4;
const byte sclkPin1 = 5;
Sensirion sht1 = Sensirion(dataPin1, sclkPin1);
unsigned int rawData1;
float temperature1;
float humidity1;
byte stat1;
**//////////////////////////// Illumination sensor ////////////////////////**
int sensorPin = A0; // Select the input pin for the potentiometer
int sensorValue = 0; // Variable to store the value coming from the sensor
long int pardata, pardata_low, pardata_hi, real_pardata;
uint16_t illumindata = 0;
void setup () {
i2c_init(); //Initialise the I²C bus
PORTC = (1 << PORTC4) | (1 << PORTC5); //Enable pullups
Wire.begin();
accel.begin(false, 2);
Serial.begin(115200);
xbee.begin(Serial);
}
void loop () {
payload[0] = 10;
payload1[0] = 11;
**/////////////////////RF temperature sensor/////////////////////////////**
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev + I2C_READ);
data_low = i2c_readAck(); //Read 1 byte and then send ack
data_high = i2c_readAck(); //Read 1 byte and then send ack
pec = i2c_readNak();
i2c_stop();
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // Zero out the data
int frac; // Data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
celcius *= 100;
int a = int(celcius) + 1;
payload[1] = a >> 8 & 0xff;
payload[2] = a & 0xff;
**//////////////////////////// Illumination sensor ////////////////////////////////**
sensorValue = analogRead(sensorPin);
TSR(sensorValue);
payload[3] = pardata_low >> 8 & 0xff;
payload[4] = pardata_low & 0xff;
**//////////////////////////// 3-axis accelemeter sensor ////////////////////////////////**
accel.update();
payload[5] = accel.getX()*10;
payload[6] = accel.getY()*10;
payload[7] = accel.getZ()*10;
delay(100);
**////////////////////////////// XBee send first packet///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, payload, sizeof(payload));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
**//////////////// SHT 1x temperature and humidity sensor /////////////////////////**
sht.readSR(&stat); // Read sensor status register
sht.writeSR(LOW_RES); // Set sensor to low resolution
sht.readSR(&stat); // Read sensor status register again
sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK)
sht.meas(TEMP, &rawData, NONBLOCK);
temperature = sht.calcTemp(rawData);
sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK)
humidity = sht.calcHumi(rawData, temperature);
sht.meas(HUMI, &rawData, NONBLOCK);
humidity = sht.calcHumi(rawData, temperature);
temperature *= 100;
a = int(temperature) + 1;
payload1[1] = a >> 8 & 0xff;
payload1[2] = a & 0xff;
humidity *= 100;
a = int(humidity) + 1;
payload1[3] = a >> 8 & 0xff;
payload1[4] = a & 0xff;
delay(10);
sht1.readSR(&stat1);
sht1.writeSR(LOW_RES); // Set sensor to low resolution
sht1.readSR(&stat1);
sht1.measTemp(&rawData1); // sht.meas(TEMP, &rawData, BLOCK)
temperature1 = sht1.calcTemp(rawData1);
sht1.measHumi(&rawData1); // sht.meas(HUMI, &rawData, BLOCK)
humidity1 = sht1.calcHumi(rawData1, temperature1);
delay(10);
temperature1 *= 100;
a = int(temperature1) + 1;
payload1[5] = a >> 8 & 0xff;
payload1[6] = a & 0xff;
humidity1 *= 100;
a = int(humidity1) + 1;
payload1[7] = a >> 8 & 0xff;
payload1[8] = a & 0xff;
**////////////////////////////// XBee send second packet ///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
zbTx = ZBTxRequest(remoteAddress,payload1, sizeof(payload1));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
}
void TSR(int sensorValue)
{
illumindata = (sensorValue * 4 * 5) / 1.5;
pardata = 6250/6144*illumindata*10;
if(pardata > 0)
{
if(pardata < 11500)
{
real_pardata = 0.0000000020561*pardata*pardata*pardata -
0.00002255*pardata*pardata +
0.25788*pardata -
6.481;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
else
{
real_pardata = 0.0000049204*pardata*pardata*pardata -
0.17114*pardata*pardata +
1978.7*pardata -
7596900;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
}
else
{
pardata_hi = 0;
pardata_low = 0;
}
}
as I am writing this I have solved the same problem you have, though with similar hardware setup. I have used bare avr atxmega128a3u (so no arduino board) and an Xbee S1 communicating on baud rate 115200. After a few days trying to figure this out I came to conclusion, that if your avr is not running at precise clock (external xtal) and you use slightly "faster" baud rate ( >= 115200 ) Xbee's serial hardware has probably trouble recovering clock signal resulting in errors in transmission. (Maybe Xbee has slow bit sampling rate).
Anyway, by ensuring your microprocessor is running at stable clock (you should be safe here 'cause arduino has an external xtal) and by using slower baud rate (try 57600, 19200 or 9600) should solve your problem. I hope so. :) ...And don't forget to reconfigure Xbee's baud rate in XCTU.
And also it might help if you initliaze xbee only once.Move these lines into setup() function:
setup(){
// This is changed
Serial.begin(9600);
// This is new
xbee = XBee();
xbee.begin(Serial);
// ...
}
EDIT: Also you might be interested in this website where you can see what is the % of error for given clock frequency and baud rate (as well as direct register values to set if you were using bare avr) http://www.wormfood.net/avrbaudcalc.php?postbitrate=9600&postclock=16&hidetables=1