I am trying to establish UART communication between a PC and a STM32f407-DISC1 board using an arduino nano as a middle man.
The PC sends 'r' to the arduino to indicate a request.
The request is then communicated to the stm32 with a GPIO interrupt, which then should be transmitting 480 bytes of data using HAL_UART_Transmit_IT.
It however sends the data twice, with only a single request made.
The code on the STM32 is generated by STM32CubeMX
Data request made by the arduino
void loop() {
digitalWrite(4, 0); // Clear EXTI11 line.
if (mySerial.available() && received < 480) { // STM32 sending data and is not done.
buff[received] = mySerial.read(); // Append received data to the buffer.
received++;
}
if (received >= 480) { // If the buffer is full
received = 0; // transmit it to PC.
Serial.println(buff);
}
if (Serial.available()) {
if (Serial.read() == 'r') { // PC requests data from the STM32
digitalWrite(4, 1); // Triggers STM32 EXTI11 line.
while (Serial.available()) // Empty the buffer.
Serial.read();
}
}
}
data transmission on the STM32
void EXTI15_10_IRQHandler(void)
{
// Make sure that the interrupt is the good one.
if (HAL_GPIO_ReadPin(data_req_IRQ_GPIO_Port, data_req_IRQ_Pin)) {
if (is_sending_data == FALSE) // If no transmission is happening
should_send_data = TRUE; // raise transmission flag.
}
// IRQ handling stuff...
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart) {
is_sending_data = FALSE; // Transmition is completed, unblock requests.
}
void main(void){
// Init and other stuff...
while (1) {
if (should_send_data == TRUE) { // If data was requested
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
is_sending_data = TRUE; // Block requests.
should_send_data = FALSE; // Clear flag.
}
// matrice acquisition stuff here
}
}
Alright so I found a solution, but it involved just rethinking my approach, so sorry for those looking for an answer to this problem.
I removed the arduino middle man by replacing it with a USB to RS232 converter and made UART reception work by interrupt. The STM detects the 'r' character which triggers the data communication.
Here is the interrupt part:
void USART3_IRQHandler(void)
{
if (USART3->SR & UART_IT_RXNE) { // If a byte is received
rxBuff[0] = (uint8_t) (huart3.Instance->DR & (uint8_t) 0xFF); // Read it.
__HAL_UART_FLUSH_DRREGISTER(&huart3); // Clear the buffer to avoid errors.
rx_new_char_flag = TRUE; // Raise the new_char flag.
return; // Stops the IRQHandler from disabling interrupts.
}
}
and the gestion of that in the main
while (1) {
if (rx_new_char_flag == TRUE) {
rx_new_char_flag = FALSE;
if (rxBuff[0] == 'r') {
rxBuff[0] = 0;
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
}
}
On the PC side, to optimize performance, instead of waiting for the full 480 bytes, I wait for only one character, if one is received I keep reading the serial port, as shown in the code bellow
int i = 0;
do {
ReadFile(m_hSerial, &temp_rx[i], 1, &dwBytesRead, NULL);
i++;
} while (dwBytesRead > 0 && i < 480);
for (int j = i; j < 480; j++) // If the transmission is incomplete, fill the buffer with 0s to avoid garbage data.
temp_rx[j] = 0;
if(i>=480) // If all the bytes has been received, copy the data in the working buffer.
std::copy(std::begin(temp_rx), std::end(temp_rx), std::begin(m_touch_state));
This works well with pretty decent performance, so that may be a permanent solution to my problem.
Related
I use this board from Heltec automation, which has LoRa and an OLED display onboard.
I do not use the Heltec library, instead I use the lora.h library directly.
When I want to adjust the spreading factor and transmitting power, these settings are not applied and there is no change in the signal. Also I have read different registers regarding spreading factor and transmitting power before and after setting and there is no change.
In summary, when I try this, nothing happens.
LoRa.setTxPower(20);
LoRa.setSpreadingFactor(12);
The code:
#include <Arduino.h>
#include <LoRa.h>
#include <Wire.h>
#include <SSD1306Wire.h>
SSD1306Wire display(0x3c, SDA_OLED, SCL_OLED, GEOMETRY_128_64);
const int csPin = 18; // LoRa radio chip select
const int resetPin = 14; // LoRa radio reset
const int irqPin = 26; // change for your board; must be a hardware interrupt pin
String outgoing; // outgoing message
byte msgCount = 0; // count of outgoing messages
byte localAddress = 0xBB; // address of this device
byte destination = 0xFF; // destination to send to
long lastSendTime = 0; // last send time
int interval = 2000; // interval between sends
int msgLoopCounter = 0;
void setup() {
Serial.begin(115200);
while (!Serial);
// Set OLED reset pin to HIGH
pinMode(RST_OLED, OUTPUT);
digitalWrite(RST_OLED, HIGH);
delay(1000);
// Initialze OLED display
if (!display.init()) {
display.setContrast(255);
display.clear();
display.display();
while (true);
}
Serial.println("Display init succeeded.");
// Initialize LoRa
LoRa.setPins(csPin, resetPin, irqPin); // set CS, reset, IRQ pin
LoRa.setTxPower(20);
LoRa.setSpreadingFactor(12);
if (!LoRa.begin(868E6)) {
Serial.println("LoRa init failed. Check your connections.");
while (true);
}
Serial.println("LoRa init succeeded.");
}
void sendMessage(String outgoing) {
LoRa.beginPacket(); // start packet
LoRa.write(destination); // add destination address
LoRa.write(localAddress); // add sender address
LoRa.write(msgCount); // add message ID
LoRa.write(outgoing.length()); // add payload length
LoRa.print(outgoing); // add payload
LoRa.endPacket(); // finish packet and send it
msgCount++; // increment message ID
}
void loop() {
if (millis() - lastSendTime > interval) {
String message = "HeLoRa!";
sendMessage(message);
Serial.println("Sending " + message);
lastSendTime = millis();
display.clear();
display.drawString(0, 0, String(lastSendTime));
display.display();
}
}
I also tried to set the values after LoRa.begin(), but then nothing is received by the receiver.
NOTE: It can't be the board itself, since I have several and have tried it with each one.
I have been working on this for almost 3 weeks now and cannot find a solution. I am trying to output information from my Teknic ClearCore to a Kinco HMI (GL070E) by ANY means. I have tried both Serial communication (RS232) and Ethernet (still lost on this but I attempted the modbus technique). below are some links to things I have tried for this. the best one seems to be the Tools40 modbus library, but clearcore doesn't support that i guess. please help.
https://github.com/IndustrialShields/arduino-Tools40
https://www.youtube.com/watch?v=W-7s52zUVng
https://www.youtube.com/watch?v=KRno6stglPk&list=PL10EF6AF38416A66F&index=4
below is my code and it's a mess because I'm panicking:
#include "ClearCore.h"
// Defines the analog input to control commanded velocity
#define Estop ConnectorDI8 //Estop
#define counter ConnectorIO2 //induction3
// Select the baud rate to match the target device.
#define baudRate 9600
int count = 0;
int d = 1;
int x = 0;
int r = 0;
void setup() {
// Put your setup code here, it will only run once:
// Sets up serial communication and waits up to 5 seconds for a port to open.
// Serial communication is not required for this example to run.
Serial.begin(baudRate);
uint32_t timeout = 5000;
uint32_t startTime = millis();
while (!Serial && millis() - startTime < timeout)
{
continue;
}
//Configure Serial communication to HMI.
// Configure COM-0 for RS-232 mode.
ConnectorCOM0.Mode(Connector::RS232);
// Set the data baud rate.
ConnectorCOM0.Speed(9600);
// (Optional) Set the data frame parity.
ConnectorCOM0.Parity(SerialBase::PARITY_E);
// (Optional) Set each data frame to use 2 stop bits.
ConnectorCOM0.StopBits(2);
// (Optional) Enable flow control.
//ConnectorCOM0.FlowControl(true);
// Open the serial port to enable data transmission.
ConnectorCOM0.PortOpen();
}
void loop() {
/****Reset circuit***************************************************************************************************/
if (ConnectorIO1.State()==HIGH && r == 1)
{
digitalWrite(IO0, true);
delay(300);
r = 0;
}
/****Estop circuit***************************************************************************************************/
while (ConnectorDI8.State()==LOW)
{
r = 1;
digitalWrite(IO0, false);
}
if (r==0)
{
Serial0.write(count);
Serial.println(count);
/****COUNTER*****************************************************************************************/
if (ConnectorIO2.State() == HIGH)
{
count++;
}
}
}
I m using dspic33f series micro controller to receive SMS from modem SIM800A. I m using interrupt method to receive response from the modem using serial communication . If I send more than one AT command to modem via UART sequentially I'm getting response into the recieve buffer only for 1st command and no response in the receive buffer for the remaining commands though the modem was responding.
After debugging I found the reason for this peculiar behavior. The reason was I was clearing the receive buffer after receiving the response into the buffer and printing on the console i.e. before sending next command to modem via UART using memset function in c.
But on commenting this memset function i was able receive the response into the receive buffer for the all the AT commands that was sent sequentially, if the memset function is not commented then no response is filled in the receive buffer though the modem was responding so please help out in receiving the response into the buffer.
Code which i have written
#include "p33FJ64GS606.h"
#include <stdio.h>
#define FCY 40000000UL
#include <libpic30.h>
#include <string.h>
_FOSC(FCKSM_CSECMD & OSCIOFNC_OFF)
_FWDT(FWDTEN_OFF)
_FPOR(FPWRT_PWR128 )
_FICD(ICS_PGD1 & JTAGEN_OFF)
char StringLoop[161];
void Init_Uart1(int uart_no)
{
U1MODEbits.STSEL = 0; // 1-Stop bit
U1MODEbits.PDSEL = 0; // No Parity, 8-Data bits
U1MODEbits.ABAUD = 0; // Auto-Baud disabled
U1MODEbits.BRGH = 0; // Standard-Speed mode
U1BRG = UBRG1_VALUE; // Baud Rate setting for 115200
U1STAbits.UTXISEL0 = 0; // Interrupt after one TX character is transmitted
U1STAbits.UTXISEL1 = 0;
U1STAbits.URXISEL0 = 0;
U1STAbits.URXISEL1 = 0;//jkv
IEC0bits.U1RXIE = 1;
IEC0bits.U1TXIE = 0; // Enable UART TX interrupt
U1MODEbits.UARTEN = 1; // Enable UART
U1STAbits.UTXEN = 1; // Enable UART TX
U1MODEbits.USIDL=0;
}
void UART1_puts(unsigned char data)
{
while (U1STAbits.TRMT==0);
U1TXREG = data;
}
void UART1_send(unsigned char *s)
{
memset(StringLoop,'\0',sizeof(StringLoop)); /* if I comment this line then i can receive the response into the buffer StringLoop continuously else i receive the response only for the 1st AT command and I don't get the response for other AT commands into the StringLoop though the modem is responding*/
while(*s)
{
UART1_puts(*s);
s++;
}
}
void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
if(IFS0bits.U1RXIF)
{
StringLoop[rcindex++] = U1RXREG;
if (rcindex >= (sizeof(StringLoop) - 1))
rcindex = 0;
}
IFS0bits.U1RXIF=0;
}
}
void main()
{
int i=0,j=0;
Init_Clocks();
Init_Uart2(1);
Init_Uart1(1);
TRISFbits.TRISF1=0;
LATFbits.LATF1=1;
UART1_send("AT+CMGR=1\r\n");
__delay_ms(2000);
printf("stringloop is %s\n",StringLoop);
UART1_send("AT+CPMS=?\r\n");
__delay_ms(2000);
printf("stringloop is %s\n",StringLoop);
UART1_send("AT+CPMS?\r\n");
__delay_ms(2000);
printf("stringloop is %s\n",StringLoop);
}
I am currently working on RS485 usart interrupts on AT32UCB1258 custom board and struggling with txempty interrupt.
Basically, I want to disable tx after 5 bytes have been sent.
My rx interrupt (receive command from master board) and tx ready interrupts are firing correctly, however, tx empty interrupt is not firing at all.
I am checking channel status register to distinguish which interrupt to be fired in the USART2 interrupt handler.
Any help is greatly appreciated. Thanks in advance!
//***********************USART INT HANDLER***************************************
__attribute__((__interrupt__)) static void rs485Interrupt(void)
{
if(AVR32_USART2.CSR.rxrdy)
{
gpio_set_pin_low(AVR32_PIN_PA08);
AVR32_USART2.IDR.txrdy = 1;
AVR32_USART2.IDR.txempty = 1;
rs485RxInterrupt();
}
else if(AVR32_USART2.CSR.txrdy)
{
AVR32_USART2.IDR.rxrdy = 1;
AVR32_USART2.IDR.txempty = 1;
rs485TxInterrupt();
}
else if(AVR32_USART2.CSR.txempty)
{
gpio_set_pin_low(AVR32_PIN_PA06);
rs485TxEmpty();
}
}
//**********************************************************************************
// this function is in main, and calls txrdy interrupt if data is available to send
static void rs485_write(void)
{
gpio_set_pin_high(AVR32_PIN_PA10);
txBuf[0] = ATEAddress;
AVR32_USART2.THR.txchr = txBuf[0];
tx_outctr = 1;
txLength = 5;
//txempty_flag = false;
txBuf[1] = peaks[loop][0];
txBuf[2] = peaks[loop][1];
txBuf[3] = peaks[loop][2];
txBuf[4] = peaks[loop][3];
AVR32_USART2.IER.txrdy = 1;
}
//************************TX INTERRUPT ROUTINE******************************************
static void rs485TxInterrupt(void)
{
//gpio_set_pin_low(AVR32_PIN_PA06);
for(tx_outctr=1; tx_outctr<=5; tx_outctr++)
{
//AVR32_USART2.THR.txchr = 0x01;
AVR32_USART2.THR.txchr = txBuf[tx_outctr];
//usart_write_char(&AVR32_USART2,(int)txBuf[tx_outctr]);
if (tx_outctr == 5)
{
// if 5btyes are sent, disable tx by causing txempty interrupt
AVR32_USART2.IDR.txrdy = 1;
AVR32_USART2.IER.txempty = 1;
txempty_flag = true;
}
}
//gpio_set_pin_low(AVR32_PIN_PA08);
}
//**********************************************************************************
Currently, watching gpio_pin06 going low if there is txempty interrupt, but never going to that stage.
I think usart initilisations, gpio enabling modules and interrupt registerations are correctly set since other interrupts are firing correctly.
I'm able to receive with the following code, but unfortunately, nothing is sent back. What am I doing wrong?
#include <pic18f25k80.h>
#include "config.h"
#include <usart.h>
int i = 0;
unsigned char MessageBuffer[200];
void main() {
OSCCONbits.IRCF = 0b110; // 8MHz
TRISB6 = 0; // TX set as output
TRISB7 = 0; // RX set as output
// Clear TX interrupt
// Set RX interrupt
// 8-bit Asynch. mode
// BRGH = 1 = high baud mode
// 51 = ((8MHz/baud)/16)-1 with baud = 9600
Open2USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE
& USART_EIGHT_BIT & USART_BRGH_HIGH, 51 );
RC2IF = 0; // reset RX2 flag
RC2IP = 0; // not high priority
RC2IE = 1; // Eneble RX2 interrupt
INTCONbits.PEIE = 1; // enable peripheral interrupts
INTCONbits.GIE = 1; // enable interrupts
RCSTA2bits.SPEN = 1; // enable USART
while(1){
}
}
void interrupt ISR () {
if(PIR3bits.RC2IF == 1) {
if(i<200) { // buffer size
MessageBuffer[i] = Read2USART(); // read byte from RX reg
if (MessageBuffer[i] == 0x0D) { // check for return key
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i=0;
return;
}
i++;
RC2IF = 0; // clear RX flag
} else {
puts2USART(MessageBuffer);
for(;i>0;i--)
MessageBuffer[i] = 0x00; // clear array
i = 0;
return;
}
}
}
I'm transmitting the 0x41 hex code, I checked with the scope and see that is is being received. And according to the code I have, an echo of the received data should be sent back. When I check the TX pin, nothing is happening.
Add USART_CONT_RX to Open2USART to enable continuous receive.
Also, it's a good idea to do the minimum necessary in the interrupt service routine. Consider something like:
void interrupt ISR () {
char data;
if(PIR3bits.RC2IF == 1) {
data = Read2USART(); // always read byte from RX reg (clears RC2IF)
if(i<200) { // buffer size
MessageBuffer[i] = data; // read byte from RX reg
i++;
}
else{
// flag buffer full error
}
}
}
and doing the rest of what you are doing in the while(1) loop.