2016-11-20 05:21 AM
Hello,
I am posting on any thread 1st time so don't know if i m writing it right.I am using STM32f103V8T6 and reserved 2kb for storing my settings in location start address 0x0800F000 and end address 0x800 reserved for ROM 2 in keil. The code i am using consumes 46k and uses 3 Usart, 1 i2c and other i/o(s). 1 Usart is reserved for MODBUS communication. The issue i am facing is when i get bulk noise from modbus, my STM32's Flash which has settings, gets erased randomly!. (erase means a garbage value takes place where a proper setting lied before noise generation). It does not effect areas in sequence e.g. last of flash or mid of flash. Noise just wipes out random portion of settings.2016-11-20 07:06 AM
I'd start by disabling all flash unlocking, erasing and writing code you have in the project, and see if it still happens.
What is this ''noise'' you are talking about? If you think you have issues in your supplies, address that.2016-11-20 07:52 AM
Thanks for prompt response.
I am using a MODBUS device on a machine ''X'', that operates at 200+volts and 400+amps. The controller (STM32) i am using is acting as modbus master for an energy meter that's been installed on ''X''. Randomly stm32's flash where i save settings, got erased over the time period of 24 hours and i monitored it more than once in more than one STM32 based devices having same firmware installed in same manner.To simulate that scenario i tried different things but one was successful, i.e. took A and B of modbus module and grounded it on ''X'''s body too frequently, after doing it 5-10 times when i rebooted STM, its settings were gone. I repeated it more than once and results are same.Previously address was 0x0800F000 to 0x800 but now i moved my settings back a little bit to 0x0800E000 to 0x800 and STM is behaving a little bit better but few settings still get erased on that noise. Any suggestions!?2016-11-20 11:47 AM
Hello,
Could you please post the MODBUS part of your code??? Because I'm trying to design a master MODBUS controller to communicate with some MODBUS panels, but unfortunately I couldn't achieve it yet. I'll be greatly thankful if you could help me in that. All the best, Mujtaba Hossaini2016-11-20 07:07 PM
I am assuming you know the basics of modbus, so i am skipping to the code direclty.
This part goes into your main where u send request to modbus slave by this function.void
read_modbus_device(
void
)
{
char
ch[10];
uint8_t lowByte=0;
uint8_t highByte=0;
uint16_t crc=0;
uint8_t mDevID = slaveid;
uint8_t startAddressLow = 0x00;
//to get data from//see machine's datasheet
uint8_t startAddressHigh = 0x1C;
//upper address//see machine's datasheet
uint8_t lengthLow = 0x00;
//length lower byte
uint8_t lengthHigh = 0x34;
//length higher byte of how many registers you need
modbusdatasize = 6;
//(id,functioncode,lowaddres,highadd,lowlenght,highlength) = 6
modubsreplysize = (lengthHigh * 2) + 4;
sprintf(ch,
''%c%c%c%c%c%c''
,mDevID,0x03,startAddressLow,startAddressHigh,lengthLow,lengthHigh);
crc = ModRTU_CRC(ch, modbusdatasize);
//calculate crc from the packet i just made
lowByte = crc & 0xFF;
//separate crc into its lower byte
highByte = crc>>8;
//separate crc into its higher byte
printf(
''%c%c%c%c%c%c%c%c''
,mDevID,0x03,startAddressLow,startAddressHigh,lengthLow,lengthHigh,lowByte,highByte);
}
I do not suggest you to use this code to begin with, it may not help at all. Go step by step with your machine and 1st try to read it manually instead of a processor. Connect your machine's MODBUS usart to a PC or Laptop via usb to 485 converter or serial to 485 converter. Now read datasheet for machine's MODBUS registers and send them using a terminal program. When you are successful doing that, i m sure u'll be able to do it with any processor.
2016-11-20 10:17 PM
Hello,
thanks for your quick reply. I've already done that and connected the device to PC and read and write in that using PC. My problem is my USART and TIMER interrupts to send/receive data to/from it. When I configure just Timer and disable the USART, the TIMER interrupt works, when I disable the TIMER and enable the USART transmitting interrupts ( TXE interrupt and TC interrupt), it also works. The problem lies within the receiving part. There's a problem with my receiving and when I enable it, neither of them work. My interrupt routine code is shown bellow:
void USART1_IRQHandler(void)
{
if((USART1->SR & 0x80)==0x80)
{
//If the buffer is fully transmitted:
if(TxCount == TxLength)
{
//Set DE pin to low level (TC interrupt is occured ):
GPIOA->BRR = GPIO_Pin_2;
GPIOA->BSRR = GPIO_Pin_3;
GPIOC->BRR=GPIO_Pin_6;
//Disable the USART1 Transmit Complete interrupt:
USART_ITConfig(USART1,USART_IT_TC, DISABLE);
USART_ITConfig(USART1,USART_IT_TXE, ENABLE);
USART_ClearFlag(USART1,USART_FLAG_TC);
TxCount=0;
//ReceiveComplete=0;
//Enable USART1 RXNE Interrupt:
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
}
else if (TxCount == TxLength-1)
{
if(USART_GetFlagStatus(USART1,USART_FLAG_TXE)!=RESET)
{
USART1->DR = write_led1_on[TxCount++];
//Disable USART TXE interrupt:
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
//Enable TC interrupt at the last byte to transmit:
USART_ITConfig(USART1, USART_IT_TC , ENABLE);
}
}
else if(TxCount != 0) //if it's not the first byte
{
//USART1 Tx empty interrupt has occured:
if(USART_GetFlagStatus(USART1,USART_FLAG_TXE)!=RESET)
{
//Continue the buffer transmission via USART:
USART1->DR = write_led1_on[TxCount++];
}
}
else if(TxCount==0)//The first byte to be transmitted:
{
//USART1 Tx empty interrupt has occured:
if(USART_GetFlagStatus(USART1,USART_FLAG_TXE)!=RESET)
{
//USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
//Set DE pin to high level:
GPIOA->BSRR = GPIO_Pin_2;
GPIOA->BRR = GPIO_Pin_3;
GPIOC->BSRR=GPIO_Pin_6;
//Transmit the first byte:
USART1->DR = write_led1_on[TxCount++];
}
if(TxLength == 1 )
{
//Enable TC interrupt at the last byte to transmit (single byte):
//Enable USART TC interrupt:
USART_ITConfig(USART1, USART_IT_TC , ENABLE);
//Disable USART TXE interrupt:
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
else if((USART1->SR & 0x20)==0x20)
{
if(RxCount>2)
{
if(RxCount<
RxBuffer
[2]+2+3-1)
{
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=RESET)
{
//Continue the buffer transmission via USART:
RxBuffer[RxCount++]=USART1->DR;
}
}
else if(RxCount==RxBuffer[2]+2+3)
{
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=RESET)
{
RxBuffer[RxCount++]=USART1->DR;
//The last byte (CRC high byte) received and the reception is complete.
ReceiveComplete=1;
USART_ITConfig(USART1, USART_IT_RXNE,DISABLE);
RxCount=0;
GPIOA->BSRR=GPIO_Pin_2;
GPIOA->BRR = GPIO_Pin_3;
GPIOC->BSRR=GPIO_Pin_6;
}
}
}
else
{
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=RESET)
{
//Continue the buffer transmission via USART:
//Receving the device address and function code data length:
RxBuffer[RxCount++]=USART1->DR;
}
}
}
2016-11-20 10:55 PM
By your attached code i don't understand what you are trying to achieve from TIMER but if you are saying you need interrupt based USART then following is the code i use.
void
USART1_IRQHandler(
void
)
{
int
deviceID;
if
( USART_GetITStatus(USART1, USART_IT_RXNE) )
{
char
t = USART1->DR;
modbusBuffer[modbusindex] = t;
modbusindex+=1;
//the packet size you calculated while sending query to
//machine is modubsreplysize
if
(modbusindex>modubsreplysize)
{
modbusBuffer[modbusindex]=
'\0'
;
deviceID = modbusBuffer[0];
if
(deviceID == slaveid)
{
uint8_t lowByte=0;
uint8_t highByte=0;
uint16_t crc=0;
crc = ModRTU_CRC(modbusBuffer, modubsreplysize);
lowByte = crc & 0xFF;
highByte = crc>>8;
//compare crc if ok then
if
(lowByte == modbusBuffer[modbusindex-1] && highByte == modbusBuffer[modbusindex])
{
//your code goes here. all data is in modbusBuffer[] just access its elements and get data u want.
}
}
modubsreplysize=0;
modbusindex=0;
memset(modbusBuffer,
'\0'
,
sizeof
(modbusBuffer));
}
}
}
2016-11-24 12:20 PM
Hello,
thanks for sending codes. They are really helpful. I'm using timer to create frame space and as a time to wait for a response from a slave device to the master query. Haven't you used any timers in your device?