Other Parts Discussed in Thread: MSP430F5508
Hi,
I am trying to build a FT232R like USB-UART IC with MSP430F5508. What it does is, collect data from the UART RXD pin on MSP430F5508, relay data to PC via USB-CDC; and also send data received from USB-CDC to the UART TXD pin on MSP430F5508. Something like the following d
[Data Acquisition Module] <-UART-> [MSP430F5508] <-USB-> [PC]
So far I was able to get data flow from Data Acquisiton Module --> UART --> USB --> PC work. But not the other way around.If I try to send some data to MSP430F5508 from a terminal program, the whole MSP430 program crashes and becomes non-responsive.
The following is the code I put together, largely modified from USB-CDC lookback example
#include <string.h>
#include "driverlib.h"
#include "USB_config/descriptors.h"
#include "USB_API/USB_Common/device.h"
#include "USB_API/USB_Common/usb.h" // USB-specific functions
#include "USB_API/USB_CDC_API/UsbCdc.h"
#include "USB_app/usbConstructs.h"
#include "hal.h"
// Global flags set by events
volatile uint8_t bCDCDataReceived_event = FALSE; // Flag set by event handler to indicate data has been received into USB buffer
#define BUFFER_SIZE 512
char dataBuffer[BUFFER_SIZE] = "";
char nl[2] = "\n";
uint16_t count;
//Select Baud rate of UART
//
//*****************************************************************************
#define BAUD_RATE 9600
//*****************************************************************************
uint8_t uartReceivedData[2];
char temp = 'R';
uint8_t ReceiveError = 0, SendError = 0;
/*----------------------------------------------------------------------------+
| Main Routine |
+----------------------------------------------------------------------------*/
void main (void)
{
WDT_A_hold(WDT_A_BASE); // Stop watchdog timer
// Minimum Vcore setting required for the USB API is PMM_CORE_LEVEL_2 .
PMM_setVCore(PMM_CORE_LEVEL_2);
USBHAL_initPorts(); // Config GPIOS for low-power (output low)
USBHAL_initClocks(8000000); // Config clocks. MCLK=SMCLK=FLL=8MHz; ACLK=REFO=32kHz
USB_setup(TRUE, TRUE); // Init USB & events; if a host is present, connect
// Configure UART module reset pin P4.3 and set it high
GPIO_setAsOutputPin(GPIO_PORT_P4, GPIO_PIN3);
GPIO_setOutputHighOnPin(GPIO_PORT_P4, GPIO_PIN3);
// COnfigure UART module CTS pin P4.2 as input
GPIO_setAsInputPin(GPIO_PORT_P4, GPIO_PIN2);
//P3.4,5 = USCI_A1 TXD/RXD
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN4 + GPIO_PIN5);
//Baudrate = 9600, clock freq = 8MHz
//UCBRx = 109, UCBRFx = 0, UCBRSx = 2, UCOS16 = 0
USCI_A_UART_initParam param = {0};
param.selectClockSource = USCI_A_UART_CLOCKSOURCE_ACLK;
param.clockPrescalar = 3;
param.firstModReg = 0;
param.secondModReg = 3;
param.parity = USCI_A_UART_NO_PARITY;
param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
param.uartMode = USCI_A_UART_MODE;
param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;
if(STATUS_FAIL == USCI_A_UART_init(USCI_A1_BASE, ¶m))
{
return;
}
//Enable UART module for operation
USCI_A_UART_enable(USCI_A1_BASE);
//Enable Receive Interrupt
USCI_A_UART_clearInterrupt(USCI_A1_BASE,
USCI_A_UART_RECEIVE_INTERRUPT);
USCI_A_UART_enableInterrupt(USCI_A1_BASE,
USCI_A_UART_RECEIVE_INTERRUPT);
uint16_t i = 0;
__enable_interrupt(); // Enable interrupts globally
while (1)
{
// uint8_t ReceiveError = 0, SendError = 0;
uint16_t count;
// Check the USB state and directly main loop accordingly
switch (USB_getConnectionState())
{
// This case is executed while your device is enumerated on the USB host
case ST_ENUM_ACTIVE:
// Sleep if there are no bytes to process.
__disable_interrupt();
if (!USBCDC_getBytesInUSBBuffer(CDC0_INTFNUM)) {
// Enter LPM0 until awakened by an event handler
__bis_SR_register(LPM0_bits + GIE);
}
__enable_interrupt();
// Exit LPM because of a data-receive event, and
// fetch the received data
if (bCDCDataReceived_event){
// Clear flag early -- just in case execution breaks
// below because of an error
bCDCDataReceived_event = FALSE;
// Count has the number of bytes received into dataBuffer
count = USBCDC_receiveDataInBuffer((uint8_t*)dataBuffer, BUFFER_SIZE, CDC0_INTFNUM);
// Send the bytes received from USB into UART port
for (i = 0; i < count; i++) {
// Wait for UART module CTS pin ready to take new input first
// while(GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2));
USCI_A_UART_transmitData(USCI_A1_BASE, temp);
}
}
break;
// These cases are executed while your device is disconnected from
// the host (meaning, not enumerated); enumerated but suspended
// by the host, or connected to a powered hub without a USB host
// present.
case ST_PHYS_DISCONNECTED:
case ST_ENUM_SUSPENDED:
case ST_PHYS_CONNECTED_NOENUM_SUSP:
__bis_SR_register(LPM3_bits + GIE);
_NOP();
break;
// The default is executed for the momentary state
// ST_ENUM_IN_PROGRESS. Usually, this state only last a few
// seconds. Be sure not to enter LPM3 in this state; USB
// communication is taking place here, and therefore the mode must
// be LPM0 or active-CPU.
case ST_ENUM_IN_PROGRESS:
default:;
}
if (ReceiveError || SendError){
// TO DO: User can place code here to handle error
}
} //while(1)
} // main()
/*
* ======== UNMI_ISR ========
*/
#if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
#pragma vector = UNMI_VECTOR
__interrupt void UNMI_ISR (void)
#elif defined(__GNUC__) && (__MSP430__)
void __attribute__ ((interrupt(UNMI_VECTOR))) UNMI_ISR (void)
#else
#error Compiler not found!
#endif
{
switch (__even_in_range(SYSUNIV, SYSUNIV_BUSIFG ))
{
case SYSUNIV_NONE:
__no_operation();
break;
case SYSUNIV_NMIIFG:
__no_operation();
break;
case SYSUNIV_OFIFG:
UCS_clearFaultFlag(UCS_XT2OFFG);
UCS_clearFaultFlag(UCS_DCOFFG);
SFR_clearInterrupt(SFR_OSCILLATOR_FAULT_INTERRUPT);
break;
case SYSUNIV_ACCVIFG:
__no_operation();
break;
case SYSUNIV_BUSIFG:
// If the CPU accesses USB memory while the USB module is
// suspended, a "bus error" can occur. This generates an NMI. If
// USB is automatically disconnecting in your software, set a
// breakpoint here and see if execution hits it. See the
// Programmer's Guide for more information.
SYSBERRIV = 0; // clear bus error flag
USB_disable(); // Disable
}
}
//******************************************************************************
//
// USCI_A1 interrupt vector service routine: transfer whatever received byte directly to USB
// TO DO: add a ring buffer here, but probably not necessary. USB is much faster than UART
//
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A1_VECTOR)))
#endif
void USCI_A1_ISR(void)
{
switch(__even_in_range(UCA1IV,4))
{
//Vector 2 - RXIFG
case 2:
uartReceivedData[0] = USCI_A_UART_receiveData(USCI_A1_BASE);
// Send received byte to USB port
if (USBCDC_sendDataInBackground((uint8_t*)uartReceivedData, 1, CDC0_INTFNUM, 1)){
// Exit if something went wrong.
SendError = 0x01;
break;
}
break;
default: break;
}
}
//Released_Version_5_00_01
The code that relays data from USB-CDC to UART are line 110 and 125. If data is received from USB, then the data will be first moved to a buffer, then written to UART port byte by byte
if (bCDCDataReceived_event){
// Clear flag early -- just in case execution breaks
// below because of an error
bCDCDataReceived_event = FALSE;
// Count has the number of bytes received into dataBuffer
count = USBCDC_receiveDataInBuffer((uint8_t*)dataBuffer, BUFFER_SIZE, CDC0_INTFNUM);
// Send the bytes received from USB into UART port
for (i = 0; i < count; i++) {
// Wait for UART module CTS pin ready to take new input first
// while(GPIO_getInputPinValue(GPIO_PORT_P4, GPIO_PIN2));
USCI_A_UART_transmitData(USCI_A1_BASE, temp);
}
}
As Jens-Michael Gross mentioned in the another post, sending data to USB in ISR probably is not a good idea. But this seems not a problem in my case. My problem is, I cannot relay data from USB to UART.
One thing I can think of is, USB is much faster than UART, so I included a CTS pin, but that doesn't help.
The other possible problem is in timing of UART. The curreent setting is, UART clock is sourced from ACLK(REO, 32768Hz). UCBRx, UCBRFx, and UCOS16 values were calculated by the tool in CCS. I also tried to source UART clock from SMCK(8MHz), and that didn't help. Although if I simply let UART pin lookback, that seems work just fine.
What else am I doing wrong here? Please advise. And thanks in advance.