To probe the windows serial port I have written this program. I set the serial port baudrate to 115200 bps. When I run this program the elapsed time is 1250 ms, so that, the baudrate only reachs 102400 bps. I also check in reception the baudrate with a similar program and the baudrate is the same.
Here is the program:
char* message =
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
int numBytes = 144;
c0 = clock()
for (;;)
{
sendSerial(&hCom, message, numBytes );
tx +=numBytes;
//14400 bytes * 8 = 115200 bps
if (tx >= 14400)
{
c1 = clock();
runtime_diff_ms = (c1 - c0) * 1000. / CLOCKS_PER_SEC;
printf("Tx frames %d Time ms %f", tx, runtime_diff_ms);
system ("pause");
return -1;
}
}
bool sendSerial(HANDLE *hCom, char *WriteBuffer, DWORD dwBytesToWrite)
{
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
bErrorFlag = WriteFile(
*hCom, // open file handle
WriteBuffer, // start of data to write
dwBytesToWrite, // number of bytes to write
&dwBytesWritten, // number of bytes that were written
NULL);
...
}
These are my serial port specifications:
DCB dcbSerialParams;
COMMTIMEOUTS timeouts;
dcbSerialParams.BaudRate=CBR_115200;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
timeouts.ReadIntervalTimeout=MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier=MAXDWORD;
timeouts.ReadTotalTimeoutConstant=5000; // 5sec
timeouts.WriteTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=100;
Anyone know how to fix this problem to reach 115200 bps?
There are 10 bits per character - 8 bits for the data plus a start and stop bit.
If you calculate how long 14400 characters at 10 bits per character should take at 115200 bps then you get 1250 ms:
(14400 characters * 10 bits/character) / (115200 bits/second) = 1.250 seconds
Related
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've attached an image showing my oscilloscope readout which is from the code below. Context: I have a Pi and a PIC which need to communicate through UART connection. I've implemented my own flow control which can be seen in the image attached [RTS = Yellow Trace, CTS = Blue Trace, Rx = Green Trace]. The code runs through and is caught in the final switch case statement which turns on an LED. But when i debug the code, no values (well the only value which is read is zero) are read in. At first i thought that i'd configured my PIC clock wrong (which is used to derive the baud rate), but i don't think this is the case. Second i through the FIFO buffer was full of zeros only and considering that i'm sending only four packets of information to the PIC, and my FIFO is 4 registers deep that this was the reason why non of the information was appearing. So i executed a code which removes the dummy bytes but this did not work.
All that is received:
0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0> etc
I got the right settings selected: baud rate: 9600 data bits: 8 parity: none stop bits: 1
If anyone is willing to spend some time looking at my code, can you see any obvious errors?
https://i.stack.imgur.com/aQoAL.jpg
Minimum Reproducible Example
# include <xc.h>
# include <math.h>
# include <stdio.h>
# include <stdio.h>
//Configuration Bits
#pragma config FNOSC = FRCPLL // Internal Fast RC Oscillator (8MHz)
#pragma config FPLLIDIV = DIV_2 // Divide FRC before PLL (Now 4MHz)
#pragma config FPLLMUL = MUL_20 // PLL Multiply (Now 80MHz)
#pragma config FPLLODIV = DIV_2 // Divide After PLL (Now 40MHz)
#pragma config FPBDIV = DIV_1 // Pheripheral Bus Clock (At 40KHz)
#pragma config FWDTEN = OFF // Watchdog Timer Disabled
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select
#pragma config JTAGEN = OFF // Disable JTAG
#pragma config FSOSCEN = OFF // Disable Secondary Oscillator
//*****************************UART Functions***********************************
void UART_Config (void) // Baude Rate of 9600, 8-Bit Data , 1 Stop Bit
{
U1MODEbits.BRGH = 0;
U1BRG = 259; //U1BRG = (40M/ (16 * 9.6k))) - 1
U1MODEbits.SIDL = 0; // Continue operation in SLEEP mode
U1MODEbits.IREN = 0; // IrDA is disabled
U1MODEbits.RTSMD = 0; // U1RTS pin is in Flow Control mode
U1MODEbits.UEN = 0b00; // U1TX, U1RX are enabled
U1MODEbits.WAKE = 1; // Wake-up enabled
U1MODEbits.LPBACK = 0; // Loopback mode is disabled
U1MODEbits.RXINV = 0; // U1RX IDLE state is '1'
U1MODEbits.PDSEL = 0b00; // 8-bit data, no parity
U1MODEbits.STSEL = 0; // 1 stop bit
U1STAbits.UTXINV = 0; // U1TX IDLE state is '1'
U1MODEbits.ON = 1; // UART1 is enabled
U1STAbits.URXEN = 1; // UART1 receiver is enabled
U1STAbits.UTXEN = 1; // UART1 transmitter is enabled
}
void Send_UART_Data(unsigned int c) // PIC Sending Data for Pi to Read
{
U1STAbits.UTXEN = 1; // Make sure transmitter is enabled
// while(CTS) // Optional CTS (Clear to Send) use
while(U1STAbits.UTXBF); // Wait while buffer is full
U1TXREG = c; // Transmit character
}
int Read_UART_Data (void) // PIC Reading Sent Data from Pi
{
int c;
while(!U1STAbits.URXDA) // Wait for information to be received
c = (int)U1RXREG; // Convert Character to Value
return c;
}
ADC_To_UART (unsigned int ADC)
{
unsigned int temp_A = 0x00;
unsigned int temp_B = 0x00;
// Splitting a 10 Bit Word Into 2 Bytes [aa aaaa aabb]
// Start Bit = 1 , Stop Bit = 0
// UART Transmission Pattern [1 aaaa aaaa 0 0000 00 bb]
temp_A = ADC >> 2; // MSB(8 Bits) ~ ADC[9:2] [aaaa aaaa]
temp_B = ADC & 0x003; // LSB(2 Bits) ~ ADC[1:0] [0000 00bb]
Send_UART_Data(temp_A);
Send_UART_Data(temp_B);
}
[enter image description here][1]
//*********************Enumerated Variable Declaration**************************
//Program Flow Control
enum Comm_State {Phase1A, Phase1B, Phase1C, Phase1D, Phase1E, Phase2A, Phase2B, Phase2C, Phase2D, Phase2E, Phase2F, Phase2G};
//******************************************************************************
//********************************MAIN******************************************
int main( )
{
//***************************Configuration**********************************
// I/O Definitions
#define UART_TRIS_RX TRISBbits.TRISB13 // UART RX - Reciever Pin (PPS)
#define UART_TRIS_TX TRISBbits.TRISB15 // UART TX - Transmission Pin (PPS)
#define UART_TRIS_CTS_PIC TRISAbits.TRISA4 // UART CTS_1 - Clear to Send - Output [CTS PIC]
#define UART_TRIS_RTS_PIC TRISBbits.TRISB4 // UART RTS_1 - Ready to Send - Output [RTS PIC]
#define UART_TRIS_CTS_PI TRISAbits.TRISA3 // UART CTS_2 - Clear to Send - Input [CTS PI]
#define UART_TRIS_RTS_PI TRISAbits.TRISA2 // UART_RTS_2 - Ready to Send - Input [RTS PI]
#define SPI_TRIS_SCK TRISBbits.TRISB14 // SPI SCK - Serial Clock Pin (PPS?)
#define SPI_TRIS_SDO TRISBbits.TRISB6 // SPI SDO - Serial Data Out Pin (PPS?)
#define SPI_TRIS_CS_1 TRISBbits.TRISB8 // SPI CS1 - DAC 2 Chip Select Pin (PPS?)
#define SPI_TRIS_CS_2 TRISBbits.TRISB7 // SPI CS2 - DAC 1 Chip Select Pin (PPS?)
#define AN4_TRIS TRISBbits.TRISB2 // Analogue Read 3
#define AN3_TRIS TRISBbits.TRISB1 // Analogue Read 2
#define AN2_TRIS TRISBbits.TRISB0 // Analogue Read 1
#define V_REF_TRIS_Plus TRISAbits.TRISA0 // Analogue V_REF(+) (Forms VRange)
#define V_REF_TRIS_Minus TRISAbits.TRISA1 // Analogue V_REF(-) (Forms VRange)
#define Reg_Enable_TRIS_D TRISBbits.TRISB9 // Regulator Digital Control (Output)
#define Reg_Enable_TRIS_M TRISBbits.TRISB12 // Regulator Button (Input)
// Port Input/Output Configuration [TRISB]
TRISB = 0x1004; // All of PortB set as Outputs Except for RB12 (Reg Enable) and RB2 (Input -> Analogue Input (Voltage)) (Port B) = (0000 ... 0100)
TRISA = 0x0003; // Set up A0 [Pin 2] and A1 [Pin 3] as V_REF(+) and V_REF(-) Respectively (Port B) = (0000 ... 0011)
UART_TRIS_RX = 1; // UART Receiver ~ Input
UART_TRIS_TX = 0; // UART Transmission ~ Output
UART_TRIS_CTS_PIC = 0; // UART "CTS_PIC" ~ Output
UART_TRIS_RTS_PIC = 0; // UART "RTS_PIC" ~ Output
UART_TRIS_CTS_PI = 1; // UART "CTS_PI" ~ Input
UART_TRIS_RTS_PI = 1; // UART "RTS_PI" ~ Input
SPI_TRIS_SCK = 0; // SPI Clock ~ Output
SPI_TRIS_SDO = 0; // SPI Data Output ~ Output
SPI_TRIS_CS_1 = 0; // SPI Chip Select 1 ~ Output
SPI_TRIS_CS_2 = 0; // SPI Chip Select 2 ~ Output
AN4_TRIS = 1; // Analogue Read In ~ Input
AN3_TRIS = 1; // Analogue Read In ~ Input
AN2_TRIS = 1; // Analogue Read In ~ Input
V_REF_TRIS_Plus = 1; // V_Ref(+) ~ Input
V_REF_TRIS_Minus = 1; // V_Ref(-) Differential Measurements ~ Input
Reg_Enable_TRIS_D = 0; // Regulator Digital Control (Output)
Reg_Enable_TRIS_M = 1; // Regulator Switch Control (Input)
// Peripheral Pin Select Configurations
U1RXR = 0x0011; // UART PPS Mapping
RPB15R = 0x0001; // UART PPS Mapping
// Analogue Pin Configurations
ANSELB = 0x0028; // RB0 RB1 RB2 = AN2 AN3 AN4 [0001 1100]
ANSELA = 0x0000; // Set all Analogue Inputs of Port A Off
//**************Sub-System Configurations*********************************//
// UART Control Configure
UART_Config(); //UART Control Configure
#define PIC_CTS LATAbits.LATA4 // Output Set Definition [1]
#define PIC_RTS LATBbits.LATB4 // Output Set Definition [2]
#define PI_CTS PORTAbits.RA3 // Input Read Definition [2]
#define PI_RTS PORTAbits.RA2 // Input Read Definition [1]
// Analogue Control Configure
ADC_Config(); // Configure ADC
AD1CON1SET = 0x8000; // Enable ADC
//***************Variable Declarations************************************//
enum Comm_State Communication_State = Phase1A; //Controller Variable
unsigned int temp1 = 0;
unsigned int Comms_Flag_1 = 0;
unsigned int ConFlag = 1;
unsigned int i = 1;
unsigned int UART_ADC_CV_1 = 0;
unsigned int UART_ADC_CV_2 = 0;
unsigned int ADC_CV = 0;
unsigned int UART_ADC_CC_1 = 0;
unsigned int UART_ADC_CC_2 = 0;
unsigned int ADC_CC = 0;
unsigned int DAC_CV = 0;
float I_CC = 0;
float V_CV = 0;
//***************Program Flow - Switch State Controlled*******************//
while(1)
{
switch (Communication_State)
{
case Phase1A: // Check For Pi Ready to Send CV ADC Value
//PIC_CTS = 0;
//Pic_Refresh();
PIC_RTS = 0;
PIC_CTS = 1;
if (PI_RTS == 1)
{
PIC_CTS = 0;
Communication_State = Phase1B;
}
break;
case Phase1B: // Receive CV ~ 12 Bit ADC Value [Two Data Packets with 0.01 Second Delay]
ConFlag = 1;
i = 1;
while (ConFlag == 1)
{
if (PI_RTS == 1 && i == 1)
{
UART_ADC_CV_1 = Read_UART_Data(); //Data Packet 1 Returned - MSB(Bit 15) to Bit 8
i++;
}
else if (PI_RTS == 1 && i == 2)
{
UART_ADC_CV_2 = Read_UART_Data(); //Data Packet 2 Returned - Bit (7)) to LSB(Bit 0)
}
else
{
ConFlag = 0;
}
}
Communication_State = Phase1C;
break;
case Phase1C: // Check for CC Value
delay(); //Ensure that Pi_RTS has gone low after sending last Transmission (Prevents Code from Running Away)
PIC_CTS = 1;
if (PI_RTS == 1)
{
PIC_CTS = 0;
Communication_State = Phase1D;
}
break;
case Phase1D: // Receive CC Value [Two Data Packets with 0.01 Second Delay]
ConFlag = 1;
i = 1;
while (ConFlag == 1)
{
if (PI_RTS == 1 && i == 1)
{
UART_ADC_CC_1 = Read_UART_Data(); //Data Packet 1 Returned - MSB(Bit 15) to Bit 8
i++;
}
else if (PI_RTS == 1 && i == 2)
{
UART_ADC_CC_2 = Read_UART_Data(); //Data Packet 2 Returned - Bit (7)) to LSB(Bit 0)
}
else
{
ConFlag = 0;
}
}
Communication_State = Phase1E;
break;
case Phase1E: // Calculations
// CV Calculations
temp1 = UART_ADC_CV_1 << 8;
ADC_CV = temp1 + UART_ADC_CV_2;
V_CV = ADC_CV * (4.096/4096);
DAC_CV = ADC_CV | 4096;
Comms_Flag_1 = SPI_Transfer(DAC_CV ,1); // Data Transmitted to DAC 1, Upon Transmission LED Turns Green (No Acknowledgement)
// CC Calculations
temp1 = UART_ADC_CC_1 << 8;
ADC_CC = temp1 + UART_ADC_CC_2;
I_CC = ADC_CC * (4.096/4096);
Communication_State = Phase2A;
break;
case Phase2A:
while(1)
{
LATBbits.LATB5 = 1;
}
break;
}
}
return 1;
}
In Read_UART_Data, you have:
while(!U1STAbits.URXDA)
c = (int)U1RXREG;
I think you're missing a semicolon because this is actually:
while (!U1STAbits.URXDA)
c = (int) U1RXREG;
This means that c is set only when the UART receiver is not ready.
What I think you meant is:
while (!U1STAbits.URXDA);
c = (int) U1RXREG;
I am a newbie with DACs, but basically, I have a FPGA (DE1-SOC) running Linux. Hooked up to it is a LTC2607 DAC. Everything is operating smoothly as far as Linux recognizing the DAC over I2C and everything.
My question is regarding how to generate a sinusoidal waveform using the cordic algorithm. I have an algorithm that outputs an array of 16 hex values.
{0x00003243, 0x00001DAC, 0x00000FAD, 0x000007F5, etc...}
The code that runs the I2c/DAC accepts a 16-bit "DAC Code", which then is converted to an analog output:
uint16_t LTC2607_code(float dac_voltage, float LTC2607_lsb, float LTC2607_offset)
{
uint16_t dac_code;
float float_code;
float_code = (dac_voltage - LTC2607_offset) / LTC2607_lsb; // Calculate the DAC code
float_code = (float_code > (floor(float_code) + 0.5)) ? ceil(float_code) : floor(float_code); // Round
if (float_code >= 65535.0) // Limits the DAC code to 16 bits
float_code = 65535.0;
dac_code = (uint16_t) (float_code); // Convert to unsigned integer
return (dac_code);
}
I know for direct digital synthesis you have to "interpolate" the points (voltage levels) along the sinusoid. My thinking is that I would send those value across the I2C, one-by-one, and however fast those 16 hex values are passed across the I2C (set by the Master (FPGA) clock # ~10MHz) is what frequency the sin wave will be?
The code for writing to the DAC is as follows:
int8_t LTC2607_write(uint8_t i2c_address, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
{
int fd;
int ret;
char *device;
uint8_t command_byte;
uint8_t buffer[3];
command_byte = dac_command | dac_address; // Build the DAC command byte
// Open the I2C device
device = LTC2607_get_device_name();
fd = open(device, O_RDWR);
if (fd < 0)
{
return (1);
}
// Select the desired address
ret = ioctl(fd, I2C_SLAVE, i2c_address);
if (ret < 0)
{
close(fd);
return (1);
}
// Build the I2C command
buffer[0] = command_byte;
buffer[1] = (dac_code >> 8) & 0xFF;
buffer[2] = dac_code & 0xFF;
// Write the command to the I2C bus
ret = write(fd, buffer, 3);
if (ret < 3)
{
close(fd);
return (1);
}
// Close the device
close(fd);
return (0);
}
How would I convert that string of 16 hex values into a sinusoid using the above LTC2607_write function?
I have a dsPIC33 with an explorer board 16. The entire code base is fairly lengthy but the problem is isolated to the DMA interrupt. It is not being triggered even though I have pretty much copied the Microchip UARTloopback example. I have read the Microchip manual section for both the UART and DMA thoroughly and the loopback example does work, however when it is implemented with my code it does not. I have checked my entire project to make sure that the DMA channels are not being overwritten or used anywhere else in the project. The same applies to the UART section. I will be including the entire file c file and h file. Functions to focus on are the uart_commInit, BEACON_uart_commPuts, and _DMA3Interrupt. The BEACON_uart_commPuts works and prints to the terminal. Everything compiles
uart.c
/**
* This source file contains functions for using the UARTs.
*
* #todo Write uart_monitor() or ISR to check for UART parity, framing error and DMA collisions
*
* #ingroup CSuart
* #defgroup CSuart UART
* #{
* High level functions for UART with DMA. Function names
* beginning with uart_comm... are for communicating with the transceiver. The
* UART peripheral used for the transceiver can be changed by editing the macros
* in CSuart.h.
*/
/* System & Local Includes */
#include <p33Fxxxx.h>
#include <string.h>
#include "CSdefine.h"
#include "types.h"
#include "CSuart.h"
/* Type and Constant Definitions*/
// Handshake control signals for Devboard USB
#define HS0 BIT4 // RC4
#define HS1 BIT3 // RC3
#define HS2 BIT2 // RC2
#define HS3 BIT5 // RD5
#define HS4 BIT2 // RD2
#define HS5 BIT1 // RD1
// Motherboard control signals
#define CS_SD_BAR BIT5 // RE5
#define OE_USB_BAR BIT1 // RC1
#define OE_MHX_BAR BIT2 // RE2
#define ON_SD_BAR BIT4 // RE4
#define ON_MHX_BAR BIT3 // RE3
/* Global & Local Variables */
// DMA TX and RX buffers for comm UART
static uint16 txBuff[RADIO_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 rxBuff[RADIO_RX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 tx0Buff[BEACON_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 rx0Buff[BEACON_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read from DMA rxBuff
static uint16 *lastRead0 = (uint16 *) &rx0Buff; // Points to next transfer to be read from DMA rxBuff
/* Functions */
/******************************************************************************
**** ****
** **
csk_usb_open() Enable USB on the Dev/Flight hardware
** **
**** ****
******************************************************************************/
void csk_usb_open(void) {
// Disable all control signals to avoid spurious
// writes when -OE_USB goes active (LOW).
PORTD |= (HS5+HS4+HS3 );
TRISD &= ~(HS5+HS4+HS3 );
//
// // Configure -OE_USB as an output, and make
// // it active (i.e., LOW)
PORTC &= ~OE_USB_BAR;
TRISC &= ~OE_USB_BAR;
} /* csk_usb_open() */
/******************************************************************************
**** ****
** **
csk_usb_close() // Disable USB on the Dev/flight hardware
** **
**** ****
******************************************************************************/
void csk_usb_close(void) {
// Restore -OE_USB to an input.
PORTC |= OE_USB_BAR;
TRISC |= OE_USB_BAR;
} /* csk_usb_close() */
/**
* Initializes the UART port with DMA for use for satellite comm (ie. the transceiver).
* This should be called sometime during startup.
*/
void uart_commInit(){
// Configure UART for 9600 8N1 with interrupts to the DMA module
RADIO_UMODEbits.UEN = 0b10; //UxTX, UxRX, UxCTS and UxRTS pins are enabled and used
RADIO_UMODEbits.PDSEL = 0b00; //8-bit data, no parity
RADIO_UBRG = ((Fcyc/38400)/16)-1; //9600 baud //38400 //((Fcyc/38400)/16)-1
//COMM_UBRG = 259; // 9600 baud # 80MHz
RADIO_USTAbits.UTXISEL0 = 0; // Interrupt when there is room in TX FIFO
RADIO_USTAbits.URXISEL = 0; // Interrupt when a character is received
// Configure DMA channel 1 as Comm Uart transmit
DMA1CONbits.DIR = 1; // DMA reads from SRAM, writes to peripheral
DMA1CONbits.AMODE = 00; // Addr. mode is register indirect w/ post increment
DMA1CONbits.MODE = 0b01;// One-shot, no ping-pong mode.
DMA1CONbits.SIZE = 1; // Transfer 1 byte at a time
DMA1REQbits.IRQSEL = 0b0001100; // DMA1 writes to UART1 TX (the Comm uart port.)
DMA1PAD = (volatile unsigned int) &RADIO_UTXREG; //Tell DMA module address of COMM TX register
DMA1STA = __builtin_dmaoffset(txBuff); // Tell DMA module start address of our dma tx buffer
IFS0bits.DMA1IF = 0; // Clear DMA interrupt flag
//IEC0bits.DMA1IE = 1; // Enable DMA interrupt
//Configure DMA channel 0 as Comm Uart receive
DMA0CONbits.MODE = 0b00; // Continuous no Ping-Pong mode
DMA0CNT = RADIO_RX_BUFFER_SIZE - 1;
DMA0REQbits.IRQSEL = 0b0001011; // DMA0 reads from UART1 RX (the Comm uart port.)
DMA0PAD = (volatile unsigned int) &RADIO_URXREG;
DMA0STA = __builtin_dmaoffset(rxBuff); // Tell DMA start addr. of buffer A
//DMA0STB = __builtin_dmaoffset(rxBuffB); // Tell DMA start addr. of buffer B
IFS0bits.DMA0IF = 0; // Clear DMA interrupt flag
//IEC0bits.DMA0IE = 1; // Enable DMA interrupt
DMA0CONbits.CHEN = 1; // Enable RX DMA channel only. TX channel is one-shot mode.
// UART config for CLI
BEACON_UMODEbits.STSEL = 0; //1-stop bit
BEACON_UMODEbits.PDSEL = 0; //No Parity, 8-data bits
BEACON_UMODEbits.ABAUD = 0; // Autobaud Disabled
BEACON_UBRG = ((Fcyc/9600)/16)-1; // 9600 baud # 80Mhz
BEACON_USTAbits.UTXISEL0 = 0; // interrupt after 1 Tx char is transmited
//BEACON_USTAbits.UTXISEL1 = 0;
BEACON_USTAbits.URXISEL = 0; // interrrupt after 1 Rx char is received
BEACON_UMODEbits.UARTEN = 1; // Enable UART
BEACON_USTAbits.UTXEN = 1; // Enable Uart Tx
IEC4bits.U2EIE = 0; // Enable error interrupt
//Tx config for CLI
DMA4REQ = 0x001F; // Uart2 transmiter
DMA4PAD = (volatile unsigned int) &BEACON_UTXREG;// Tell DMA module address of COMM TX register
DMA4CONbits.AMODE = 0; // Addr. mode is register indirect x/ post increment
DMA4CONbits.MODE = 1; // One-Shot
DMA4CONbits.DIR = 1; // reads from RAM writes to peripheral
DMA4CONbits.SIZE = 1;// Transfers 1 byte at a time
// count needs to be pushed into interrupt and counted there, will avoid weird shit
DMA4CNT = 7; // 11 DMA requests
DMA4STA = __builtin_dmaoffset(tx0Buff); // Tell DMA module start address of our dma tx buffer
IFS2bits.DMA4IF = 0; // Clear DMA interrupt flag
IEC2bits.DMA4IE = 1; // Enable DMA interrupt
// Rx config for CLI
DMA3REQ = 0x001E; // Uart2 Receive
DMA3PAD = (volatile unsigned int) &BEACON_URXREG; // Tell DMA module address of COMM RX register
DMA3CONbits.AMODE = 0; // Addr. mode is register indirect x/ post increment
DMA3CONbits.MODE = 2; // Ping-Pong
DMA3CONbits.DIR = 0; // reads from peripheral writes to RAM
DMA3CONbits.SIZE = 0; // Transfers 1 word at a time
DMA3CNT = 7; // 11 DMA requests
DMA3STA = __builtin_dmaoffset(tx0Buff); // Tell DMA start addr. of receive buffer
DMA3STB = __builtin_dmaoffset(rx0Buff); // Tell DMA start addr. of receive buffer
DMA3CONbits.CHEN = 1; // Enable RX DMA channel only. TX channel is one-shot mode.
IFS2bits.DMA3IF = 0; // Clear DMA interrupt
IEC2bits.DMA3IE = 1; // Enable DMA interrupt
// END of added code
// these bits must be at end of file
RADIO_UMODEbits.UARTEN = 1; //enable uart
RADIO_USTAbits.UTXEN = 1; //transmit enabled
}
/**
* Writes a string to the comm Port. The length must be less than COMM_TX_BUFFER_SIZE
* or this function will have no effect.
* #param str The string to write.
* #param len The number of bytes to write
* #pre uart_commInit() must be called before calling this function.
* #note This function call is blocking. It waits until the last transfer is
* finished to begin current transmission. Once current transmission has been
* started then it will return because the DMA module handles transmission of data.
*/
void BEACON_uart_commPuts(char *str, uint16 len){
#if DEBUG_OUTPUT
uint16 *targetAddr;
if(len == 0 || len > BEACON_TX_BUFFER_SIZE)
return; //TODO Handle error
while(!BEACON_commIsTXReady()); // Blocking!
targetAddr = (uint16 *) (DMA4STA + ((unsigned int) &_DMA_BASE)); // Address of DMA buffer
memcpy((void *) targetAddr, (const void *) str, len); // Copy data into DMA buffer
DMA4CNT = len-1; // Send len # of characters
DMA4CONbits.CHEN = 1; // Turn on the DMA channel
DMA4REQbits.FORCE = 1; // Start DMA transfer to comm UART
#endif
}
/**
* Retrieves a string from the Comm. Port. The caller must ensure that the 'str'
* parameter can handle the number of bytes being requested in parameter 'len'.
* #param str The string to store the received characters in.
* #param len The maximum number of characters to return. The number of chars
* copied to str will be less than or equal to len.
* #return int16 The number of bytes copied to str if non-negative or an error
* code if negative.
* #pre uart_commInit() must be called before calling this function.
* #todo Add overrun detection
* #todo Implement error codes if necessary.
*/
int16 RADIO_uart_commGets(char *str, uint16 len){
/* The DMA transfers 2 bytes of data into the DMA buffer for every byte it
* receives from the UART (see dsPIC33 reference manual DMA chapter). The
* lower byte is the data received by the UART and the upper byte has 2
* status bits. There is one DMA receive buffer (no Ping-Pong mode) which the
* DMA starts to fill 2 bytes at a time until the buffer is full then goes
* back to the beginning and starts to put new characters in the beginning
* of the buffer again. This code reads up to 'len' bytes (not transfers!) from the buffer
* starting from the last location readmup to the last byte available in
* the DMA buffer. If the DMA rolled over to the beginning since the last read,
* this function reads until the end of the buffer, then from the beginning.
* This should be called often enough to prevent overruns.
*
* NOTE: For every 2 bytes this function reads from the DMA buffer it only
* returns one because the upper byte of each transfer are status bits.
*/
uint16 numTransfers, i; // # of DMA transfers (not bytes!) to return to caller.
uint16 *lastArrived = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
//static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read
if(lastArrived < lastRead){ // Rollover occured
// (1) # of transfers till end of buffer.
// (2) # of transfers in the beginning of buffer.
numTransfers = (uint16) ((rxBuff + RADIO_RX_BUFFER_SIZE - 1) - lastRead);
numTransfers += (uint16) (lastArrived - rxBuff);
}else{
numTransfers = (uint16) (lastArrived - lastRead);
}
if(len < numTransfers) // Don't give caller more bytes than they can handle
numTransfers = len;
for(i = 0; i < numTransfers; i++){ // Now copy chars into caller's buffer
/*if(i == 0){
uart_commGetc();
continue;
}*/
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rxBuff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to callers buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return i; // # of bytes returned in parameter 1.
}
int16 BEACON_uart_commGets(char *str, uint16 len){
/* The DMA transfers 2 bytes of data into the DMA buffer for every byte it
* receives from the UART (see dsPIC33 reference manual DMA chapter). The
* lower byte is the data received by the UART and the upper byte has 2
* status bits. There is one DMA receive buffer (no Ping-Pong mode) which the
* DMA starts to fill 2 bytes at a time until the buffer is full then goes
* back to the beginning and starts to put new characters in the beginning
* of the buffer again. This code reads up to 'len' bytes (not transfers!) from the buffer
* starting from the last location readmup to the last byte available in
* the DMA buffer. If the DMA rolled over to the beginning since the last read,
* this function reads until the end of the buffer, then from the beginning.
* This should be called often enough to prevent overruns.
*
* NOTE: For every 2 bytes this function reads from the DMA buffer it only
* returns one because the upper byte of each transfer are status bits.
*/
uint16 numTransfers, i; // # of DMA transfers (not bytes!) to return to caller.
uint16 *lastArrived = (uint16 *)(DMA3STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
//static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read
if(lastArrived < lastRead){ // Rollover occured
// (1) # of transfers till end of buffer.
// (2) # of transfers in the beginning of buffer.
numTransfers = (uint16) ((rx0Buff + BEACON_RX_BUFFER_SIZE - 1) - lastRead);
numTransfers += (uint16) (lastArrived - rx0Buff);
}else{
numTransfers = (uint16) (lastArrived - lastRead);
}
if(len < numTransfers) // Don't give caller more bytes than they can handle
numTransfers = len;
for(i = 0; i < numTransfers; i++){ // Now copy chars into caller's buffer
/*if(i == 0){
uart_commGetc();
continue;
}*/
if(lastRead >= rx0Buff + BEACON_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rx0Buff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to callers buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return i; // # of bytes returned in parameter 1.
}
/**
* Retrieves a single character from the comm receive buffer.
* #return (int16) returns a signed integer. If the value is less than zero there
* were no characters in the UART receive buffer to return. Otherwise, the return
* value should be cast to a char and used accordingly.
* #pre uart_commInit() must be called before calling this function.
*/
int16 RADIO_uart_commGetc(){
int16 retValue;
if(RADIO_uart_commNumRXBytes() > 0){
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rxBuff; // Start reading from beginning now
}
retValue = (int16) *lastRead;
lastRead++;
return retValue;
}
return -1;
}
/**
* Retrieves a single character from the comm receive buffer.
* #return (int16) returns a signed integer. If the value is less than zero there
* were no characters in the UART receive buffer to return. Otherwise, the return
* value should be cast to a char and used accordingly.
* #pre uart_commInit() must be called before calling this function.
*/
int16 BEACON_uart_commGetc(){
int16 retValue;
if(BEACON_uart_commNumRXBytes() > 0){
if(lastRead >= rx0Buff + BEACON_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rx0Buff; // Start reading from beginning now
}
retValue = (int16) *lastRead;
lastRead++;
return retValue;
}
return -1;
}
/**
* Looks for and retrieves a string from the comm port up to and including the
* specified terminating character. If the terminating character does not exist
* in the uart buffer no characters are copied to str and -1 is returned.
* #param str A buffer to stored the received data in
* #param len Maximum number of characters to retrieve
* #param terminator the terminating character
* #return The number of characters copied to str, -1 if no terminator not found or buffer to small for command
*/
int16 uart_commGetToChar(char *str, uint16 len, char terminator){
BOOL foundChar = FALSE;
int16 i, strLen = 0; // strLen is the value we will return
uint16 *tempPtr = lastRead; // Points after the last read DMA transfer (transfer = 2 bytes)
uint16 *lastArrived = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
len = (len < (i = RADIO_uart_commNumRXBytes())) ? len : i; // If numCharsReceived > len then len = numCharsReceived
// Look for null terminating character
while(!foundChar){ // Loop until char is found or 'till end of received chars
if(strLen >= len){
return -1; // Provided buffer not long enough or terminating char not found.
}
if((char) (*tempPtr & 0xFF) == terminator){ // Found terminating char?
foundChar = TRUE;
strLen++; // To count terminating character
}else{
strLen++; // Increment # of transfers we're planning to copy to user's buffer
tempPtr++; // Increment pointer to the receive buffer
if(tempPtr >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover in rxBuff
tempPtr = rxBuff; // Start reading from beginning now
}
}
}
for(i = 0; i < strLen; i++){ // Now copy chars into caller's buffer
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover in rxBuff
lastRead = rxBuff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to caller's buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return strLen; // # of bytes INCLUDING terminating character
}
/**
* Returns the number of unread characters in the comm UART buffer.
* #return (int16) number of unread chars in comm UART buffer
* #pre uart_commInit() must be called before calling this function.
*/
int16 RADIO_uart_commNumRXBytes(){
int16 retValue;
uint16 *lastReceivedChar = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE));
if(lastReceivedChar >= lastRead){
return (int16) (lastReceivedChar - lastRead);
}else{
retValue = (int16) ((uint16 *)(&rxBuff + RADIO_TX_BUFFER_SIZE) - lastRead);
retValue += (uint16) (lastReceivedChar - (uint16 *)&rxBuff);
return retValue;
}
}
int16 BEACON_uart_commNumRXBytes(){
int16 retValue;
uint16 *lastReceivedChar = (uint16 *)(DMA2STA + ((unsigned int) &_DMA_BASE));
if(lastReceivedChar >= lastRead){
return (int16) (lastReceivedChar - lastRead);
}else{
retValue = (int16) ((uint16 *)(&rx0Buff + BEACON_TX_BUFFER_SIZE) - lastRead);
retValue += (uint16) (lastReceivedChar - (uint16 *)&rx0Buff);
return retValue;
}
}
/* Interrupt Handlers */
//void __attribute__((__interrupt__,no_auto_psv)) _U2EInterrupt(void){
// TODO Handle Uart Error
//}
/**
* Comm receive DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA0Interrupt(void){
IFS0bits.DMA0IF = 0; // Clear DMA interrupt flag
}
/**
* Comm transmit DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA1Interrupt(void){
IFS0bits.DMA1IF = 0; // Clear DMA interrupt flag
}
/**
* Comm receive DMA interrupt service routine.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA3Interrupt(void){
static unsigned int BufferCount = 0;
if(BufferCount == 0){
DMA4STA = __builtin_dmaoffset(tx0Buff);
}
else{
DMA4STA = __builtin_dmaoffset(rx0Buff);
}
DMA4CONbits.CHEN = 1; // Re-enable DMA3 channel
DMA4REQbits.FORCE = 1; // manual start the transfers, if we doing predetermined transfer size
BufferCount ^= 1;
IFS2bits.DMA3IF = 0; // Clear DMA3 Interrupt flag
}
/**
* Comm transmit DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA4Interrupt(void){
IFS2bits.DMA4IF = 0; // Clear DMA interrupt flag
}
/**
* #}
*/
uart.h
/**
* This header file provides function prototypes and macros for UART ports.
*
* #ingroup CSuart
*/
/**
* #ingroup CSuart
* #{
*/
#ifndef CSUART_H
#define CSUART_H
/* Include Files */
#include <p33Fxxxx.h>
/**
* Register definitions for Comm port uart
* Change these values to use the other uart port.
* WARNING: Must also change values in uart_commInit(). (DMA1REQbits.IRQSEL)
* #cond
*/
/*NOTE:(8/20/14, 3:53pm) these macros have been changed, U2 -> U1 */
#define RADIO_UMODE U1MODE
#define RADIO_UMODEbits U1MODEbits
#define RADIO_USTA U1STA
#define RADIO_USTAbits U1STAbits
#define RADIO_URXREG U1RXREG
#define RADIO_UTXREG U1TXREG
#define RADIO_UBRG U1BRG
#define RADIO_URXIF IFS0bits.U1RXIF // Comm uart receive interrupt flag
#define RADIO_UTXIF IFS0bits.U1TXIF // Comm uart transmite interrupt flag
#define RADIO_RXIntEnable() {IEC0bits.U1RXIE = 1;}
#define RADIO_TXIntEnable() {IEC0bits.U1TXIE = 1;}
#define RADIO_ErrorIntEnable() {IEC4bits.U1EIE = 1;}
#define RADIO_RXIntDisable() {IEC0bits.U1RXIE = 0;}
#define RADIO_TXIntDisable() {IEC0bits.U1TXIE = 0;}
#define RADIO_ErrorIntDisable() {IEC4bits.U1EIE = 0;}
#define BEACON_UMODEbits U2MODEbits
#define BEACON_USTAbits U2STAbits
#define BEACON_URXREG U2RXREG
#define BEACON_UTXREG U2TXREG
#define BEACON_UBRG U2BRG
#define BEACON_IFSbits IFS2bits
#define RADIO_TX_BUFFER_SIZE 283 /// Size of comm port's DMA transmit buffer in bytes
#define RADIO_RX_BUFFER_SIZE 128 /// Size of comm port's DMA receive buffer in bytes
#define BEACON_TX_BUFFER_SIZE 128 /// Size of comm port's DMA transmit buffer in bytes
#define BEACON_RX_BUFFER_SIZE 128 /// Size of comm port's DMA receive buffer in bytes
/**
* Returns 1 when the comm port UART is ready to transmit, and 0 otherwise.
*/
#define RADIO_commIsTXReady() (RADIO_USTAbits.TRMT)
#define BEACON_commIsTXReady() (BEACON_USTAbits.TRMT)
/* Function Prototypes */
void uart_commInit();
void BEACON_uart_commPuts(char *str, uint16 len);
void uart0_commPuts(char *str, uint16 len);
int16 RADIO_uart_commGets(char *str, uint16 len);
//int16 uart0_commGets(char *str, uint16 len);
int16 RADIO_uart_commGetc();
//int16 uart0_commGetc();
int16 uart_commGetToChar(char *str, uint16 len, char terminator);
//int16 uart0_commGetToChar(char *str, uint16 len, char terminator);
int16 RADIO_uart_commNumRXBytes();
//int16 uart0_commNumRXBytes();
/**
* #}
*/
#endif /* CSUART_H */
I'm attempting to send serial messages over USB to an Arduino Uno, using raw WinAPI commands. When using baud rates less than 115200, it works perfectly fine. However, when I send at 115200 baud, two extra bytes are sent prefixing the data I sent, but ONLY for the first message after connecting to the Arduino. For example, if I connect to the Arduino and send two bytes, "Hi", the Arduino receives "ððHi". If I send "Hi" again, the Arduino receives "Hi" like it should. (The extra bytes are usually ð (0xF0), but not always.)
I know that my computer and the Arduino are capable of communicating at 115200 baud, because other programs such as avrdude and the Arduino IDE's serial monitor can do it fine.
I have tried clearing the RX and TX buffers on both sides and also messing the DCB settings, with no effect. Does anyone know what might be causing this?
Thanks!
Here is my code to reproduce the problem:
Computer side:
#include <Windows.h>
int main()
{
// Open device as non-overlapped
HANDLE device = CreateFile(L"COM6",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Make sure the device is valid
if(device == INVALID_HANDLE_VALUE)
return 0;
DCB dcb;
if(!GetCommState(device, &dcb))
return 0;
dcb.fOutX = 0;
dcb.fInX = 0;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fNull = 0;
dcb.BaudRate = CBR_115200;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
if(!SetCommState(device, &dcb))
return 0;
COMMTIMEOUTS Timeouts = { 0 };
Timeouts.ReadTotalTimeoutConstant = 1000;
Timeouts.WriteTotalTimeoutConstant = 1000;
if(!SetCommTimeouts(device, &Timeouts))
return 0;
char *buf = "abcdef";
DWORD written;
WriteFile(device, buf, 6, &written, NULL);
DWORD read;
char inbuf[100];
ReadFile(device, inbuf, 100, &read, NULL);
// When I get the result inbuf, it has 8 bytes: {0xF0, 0xF0, a, b, c, d, e, f}
// Doing a 2nd set of Write/ReadFile, with the same message, gives the correct response
return 0;
}
Arduino side:
void setup()
{
Serial.begin(115200);
}
void loop()
{
if(Serial.available())
Serial.write(Serial.read());
}