I have recently got my hands on a Tiva C series MCU and I would like to use it's USB capabilities.
My goal is to send commadns to the boards via USB and get a message back (acknowledge or error reporting)
Commands start with a capital letter followed by 3 digits like X123.
There is a sample code which I have modified to a bit, to get certain responses if the RxBuffer has the letter in it.
static uint32_t
EchoNewDataToHost(tUSBDBulkDevice *psDevice, uint8_t *pui8Data,
uint32_t ui32NumBytes)
{
uint32_t ui32Loop, ui32Space, ui32Count;
uint32_t ui32ReadIndex;
uint32_t ui32WriteIndex;
tUSBRingBufObject sTxRing;
//
// Get the current buffer information to allow us to write directly to
// the transmit buffer (we already have enough information from the
// parameters to access the receive buffer directly).
//
USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
//
// How much space is there in the transmit buffer?
//
ui32Space = USBBufferSpaceAvailable(&g_sTxBuffer);
//
// How many characters can we process this time round?
//
ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
ui32Count = ui32Loop;
//
// Update our receive counter.
//
g_ui32RxCount += ui32NumBytes;
//
// Dump a debug message.
//
DEBUG_PRINT("Received %d bytes\n", ui32NumBytes);
//
// Set up to process the characters by directly accessing the USB buffers.
//
ui32ReadIndex = (uint32_t)(pui8Data - g_pui8USBRxBuffer);
ui32WriteIndex = sTxRing.ui32WriteIndex;
while(ui32Loop)
{
UARTprintf("\n" );
//
// Copy from the receive buffer to the transmit buffer converting
// character case on the way.
//
//
// Is this a lower case character?
//
if((g_pui8USBRxBuffer[ui32ReadIndex] == 'L'))
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
UARTprintf("LEFT" );
}
else if((g_pui8USBRxBuffer[ui32ReadIndex] == 'R'))
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
UARTprintf(" RIGHT " );
}
else
{
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
//
// Is this an upper case character?
//
if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'A') &&
(g_pui8USBRxBuffer[ui32ReadIndex] <= 'Z'))
{
//
// Convert to lower case and write to the transmit buffer.
//
g_pui8USBTxBuffer[ui32WriteIndex] =
(g_pui8USBRxBuffer[ui32ReadIndex] - 'Z') + 'z';
}
else
{
//
// Copy the received character to the transmit buffer.
//
g_pui8USBTxBuffer[ui32WriteIndex] =
g_pui8USBRxBuffer[ui32ReadIndex];
}
}
//
// Move to the next character taking care to adjust the pointer for
// the buffer wrap if necessary.
//
ui32WriteIndex++;
ui32WriteIndex = (ui32WriteIndex == BULK_BUFFER_SIZE) ?
0 : ui32WriteIndex;
ui32ReadIndex++;
ui32ReadIndex = (ui32ReadIndex == BULK_BUFFER_SIZE) ?
0 : ui32ReadIndex;
ui32Loop--;
}
//
// We've processed the data in place so now send the processed data
// back to the host.
//
USBBufferDataWritten(&g_sTxBuffer, ui32Count);
DEBUG_PRINT("Wrote %d bytes\n", ui32Count);
//
// We processed as much data as we can directly from the receive buffer so
// we need to return the number of bytes to allow the lower layer to
// update its read pointer appropriately.
//
return(ui32Count);
}
But I have no idea how to get the next 3 digits out of the buffer as numbers and simply write back messages to the host with a single command like UARTprintf for example.
Could you please get me on track with this?
Thanks guys,
Zoszko
Related
I would like to receive and transmit data that will be put into a circular buffer. I have functions for inserting characters and reading characters.
How can I use these functions and where should I put them? Currently I transmit and receive what I send to the terminal and it works fine.
I am just learning, please give me some advice
#define UART_RX_BUF_SIZE 7
#define UART_TX_BUF_SIZE 7
int8_t uart_put_char(char data);
int8_t uart_get_char(char *data);
volatile char uart_rxBuff[UART_RX_BUF_SIZE];
volatile char uart_txBuff[UART_TX_BUF_SIZE];
void uart_put_string(char *s);
typedef struct {
volatile char *const buffer;
uint8_t head;
uint8_t tail;
} circ_buffer_t;
volatile circ_buffer_t uart_rx_circBuff = {uart_rxBuff, 0, 0};
volatile circ_buffer_t uart_tx_circBuff = {uart_txBuff, 0, 0};
uint8_t received_char;
int8_t uart_put_char(char data) {
uint8_t head_temp = uart_tx_circBuff.head + 1;
if (head_temp == UART_TX_BUF_SIZE)
head_temp = 0;
if (head_temp == uart_tx_circBuff.tail)
return 0;
uart_tx_circBuff.buffer[head_temp] = data;
uart_tx_circBuff.head = head_temp;
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);
return 1;
}
int8_t uart_get_char(char *data) {
if (uart_rx_circBuff.head == uart_rx_circBuff.tail)
return 0;
uart_rx_circBuff.tail++;
if (uart_rx_circBuff.tail == UART_RX_BUF_SIZE)
uart_rx_circBuff.tail = 0;
*data = uart_rx_circBuff.buffer[uart_rx_circBuff.tail];
return 1;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
// uart_put_char(&received_char);
HAL_UART_Transmit(&huart1, &received_char, 1, 100);
// uart_get_char(received_char);
HAL_UART_Receive_IT(&huart1, &received_char, 1);
}
}
I want to put a side-note first, so it doesn't get missed:
I would suggest incrementing your head and tail indices after you've put the byte in the buffer. So, upon initialisation, head is 0. When you call put_tx, the byte will be stored at index 0 and then be incremented to 1. When the interrupt calls get_tx, the tail is still 0 so you'll get that first character, then it'll be incremented to 1. Doesn't really matter, but I think it's easier to write clean code if you think in this way.
Also, it's totally a micro-optimisation, but think about setting your buffer size to a power of 2. That way, instead of going if (head==BUF_SIZE) head=0; you can go head &= BUF_SIZE-1; and you'll save a few clock cycles, no need for a test. ;-)
It definitely is a pain to set up, but very much worth it if you can get around the multiple steps. The HAL will probably handle much of this for you, but I don't know enough about that.
You need an interrupt handler for UART events.
You need to tell the UART to raise interrupts for RXNE (receive not empty), and TXE (transmit empty) when you've sent a character.
You need to tell the NVIC to enable the UART interrupt.
I definitely recommend having push and pop (or put and get) functions for both buffers. The interrupts will call put_rx and get_tx, while user code will call put_tx and get_rx. Or better yet, write some wrapper functions, like Uart_Send(char), Uart_SendBuffer(const char*, size_t), Uart_TryReceive(char*, size_t) that will call put_tx and get_rx.
If the HAL is as smart as I think it is, you can can probably combine steps 1-3 into a single step, and just implement HAL_UART_RxCpltCallback (as you've done) and HAL_UART_TxCpltCallback.
I don't know how the HAL works enough to give you an exact solution (all my STM32 work is built on headers I made myself before I realised even CMSIS existed - whoops!) so here's how I would do it in low-level code.
void USART1_IRQHandler() __attribute__((interrupt))
{
// This would probably be handled in HAL_UART_RxCpltCallback
if (USART1->SR.RXNE) // We've received a byte!
uart_push_rx(USART1->DR); // Push the received byte onto the back
// of the RX buffer.
// This would probably be handled in HAL_UART_TxCpltCallback
if (USART1->SR.TXE) // Transmit buffer is empty - send next byte
{
char nextByte;
if (uart_pop_tx(&nextByte)) // Get the next byte in the buffer and
USART1->DR = nextByte; // shove it in the UART data register.
else // No more data in the circular buffer,
USART1->CR1.TXEIE = 0; // so disable the TXE interrupt or we'll
// end up stuck in a loop.
}
if (USART1->SR.TC) // There's also a flag for 'transmit complete'. This
{ } // is different from TXE in that TXE means "Okay, I've started this
// one, tell me what'll come next," whereas TC says "Okay, I've
// finished sending everything now. Anything else, boss?"
// We won't use it, but be aware of the terminology. The HAL might
// try and confuse you with its words.
}
void InitialiseUart()
{
HAL_UART_Configure(&huart1, baud, stopBits, andStuff, probably, etc);
HAL_UART_Enable(&huart1);
// You probably don't need to worry about anything below here,
// if the HAL is smart. But I've included it for completeness,
// so you can understand more of what the MCU is doing.
// Enable RXNE (receive not empty) interrupt
USART1->CR1.RXNEIE = 1;
// Don't enable TXE (transmit empty) interrupt yet. Only when you send
// a character, or the interrupt will fire immediately.
// Enable UART interrupts at the system level
NVIC_EnableIRQ(USART1_IRQn);
}
If you need me to, I'll look into the HAL code and try and give you some more direct guidance, but I think it's valuable to take this, understand it, and translate it to your implementation.
I've had a closer look at the HAL source code, and it looks like by using the HAL_xxxx_IT() functions, all the interrupt code is already handled for you. That said, there are a lot of similarities to doing it in bare metal in your application, since you're only sending and receiving one character at a time.
When you call __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE) you're telling the microcontroller to fire an interrupt when the data register is empty. But the HAL interrupt routine doesn't know what to transmit, so it'll send out garbage until it thinks it's finished.
I think another problem might be caused by directly accessing your circular buffer in multiple places, causing clashes. You'd be better off calling your HAL functions with a temporary buffer (or pointer to a single char) that either is taken from, or stores into, your circular buffer.
Main function
// Entry point
int main(void)
{
// Initialise system and peripherals
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM10_Init();
// Enable interrupts
HAL_NVIC_EnableIRQ(USART1_IRQn);
// Prepare reception of the first character
HAL_UART_Receive_IT(&huart1, &received_char, 1);
while (1)
{
char downloaded;
if (UartReceiveChar(&downloaded) && downloaded == 'x')
UartSendChar(downloaded);
}
}
UART wrapper
// Function declarations
int8_t UartSendChar (char data);
void UartSendString (char* str);
int8_t UartReceiveChar (char* data);
// Variables
int8_t isTransmitting = 0;
uint8_t sendingChar;
uint8_t receivedChar;
// Function definitions
// Callback function for when a character has finished sending by the HAL
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
// The HAL has just sent the tail byte from the TX buffer
// If there is still data in the buffer, we want to send the
// next byte in the buffer.
if (buffer_pop_tx(&sendingChar))
HAL_UART_Transmit_IT(huart, &sendingChar, 1);
else
isTransmitting = 0;
}
// Callback function for when a character is received by the HAL
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// The HAL has received a character into 'receivedChar'
// All we need to do is push it onto our circular buffer
buffer_push_rx(receviedChar);
// and prepare to receive the next character
HAL_UART_Receive_IT(huart, &receivedChar, 1);
}
// Send a character
int8_t UartSendChar(char data)
{
// Push the character onto the buffer
int8_t returnValue = buffer_push_tx(data);
// Start sending the buffer, if we're not already transmitting
if (!isTransmitting)
{
sendingChar = data;
isTransmitting = 1;
HAL_UART_Transmit_IT(&huart1, &sendingChar, 1);
}
return returnValue;
}
// Send a null-terminated string
int8_t UartSendString(char* str)
{
// Iterate through all the non-null characters
while (*str)
{
// Send the character; Wait if the buffer is full
while (!UartSendChar(*str)) ;
++str;
}
return 1;
}
// Receive a character
int8_t UartReceiveChar(char* data)
{
// Just a wrapper for buffer_pop_rx
return buffer_pop_rx(data);
}
Buffer implementation
// I've changed your circular buffer size for optimisation purposes
#define UART_RX_BUF_SIZE 8
#define UART_TX_BUF_SIZE 8
// Buffer type definition
typedef struct
{
volatile char *const buffer;
uint8_t head;
uint8_t tail;
uint8_t isFull : 1;
uint8_t isEmpty : 1;
uint8_t hasOverflowed : 1; // Overflow and underflow are only relevant if we choose to
uint8_t hasUnderflowed : 1; // allow pushing and popping with an empty/full buffer
} circ_buffer_t;
// Function declarations
int8_t buffer_push_tx (char data);
int8_t buffer_push_rx (char data);
int8_t buffer_pop_tx (char* data);
int8_t buffer_pop_rx (char* data);
// Variables
volatile char uart_rxBuff[UART_RX_BUF_SIZE];
volatile char uart_txBuff[UART_TX_BUF_SIZE];
volatile circ_buffer_t uart_rx_circBuff = {uart_rxBuff, 0, 0};
volatile circ_buffer_t uart_tx_circBuff = {uart_txBuff, 0, 0};
// Function definitions
// Push a character onto the transmit buffer
int8_t buffer_push_tx(char data)
{
if (uart_tx_circBuff.isFull) // buffer is full
{
// uart_tx_circBuff.hasOverflowed = 1; // Nasty things can happen if we allow overflows. But in some special cases, it may be necessary.
return 0;
}
// Put the character at the head position and increment the head index
uart_tx_circBuff.buffer[uart_tx_circBuff.head++] = data;
uart_tx.circBuff.head &= (UART_TX_BUF_SIZE - 1); // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_tx_circBuff.isFull = (uart_tx_circBuff.head == uart_tx_circBuff.tail);
uart_tx_circBuff.isEmpty = 0;
// OK
return 1;
}
// Push a character onto the receive buffer
int8_t buffer_push_rx(char data)
{
if (uart_rx_circBuff.isFull) // buffer is full
{
// uart_rx_circBuff.hasOverflowed = 1;
return 0;
}
// Put the character at the head position and increment the head index
uart_rx_circBuff.buffer[uart_rx_circBuff.head++] = data;
uart_rx.circBuff.head &= (UART_RX_BUF_SIZE - 1); // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_rx_circBuff.isFull = (uart_rx_circBuff.head == uart_rx_circBuff.tail);
uart_rx_circBuff.isEmpty = 0;
// OK
return 1;
}
// Try to get a character from the receive buffer.
int8_t uart_pop_rx(char *data)
{
if (uart_rx_circBuff.isEmpty) // buffer is empty
{
// uart_rx_circBuff.hasUnderflowed = 1;
return 0;
}
// Put the character from the tail position of the buffer into 'data' and increment the tail index
*data = uart_rx_circBuff.buffer[uart_rx_circBuff.tail++];
uart_rx_circBuff.tail &= (UART_RX_BUF_SIZE - 1); // // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_rx_circBuff.isEmpty = (uart_rx_circBuff.head == uart_rx_circBuff.tail);
uart_rx_circBuff.isFull = 0;
// OK
return 1;
}
// Try to get a character from the transmit buffer.
int8_t uart_pop_rx(char *data)
{
if (uart_tx_circBuff.head == uart_tx_circBuff.tail) // buffer is empty
{
// uart_tx_circBuff.hasUnderflowed = 1;
return 0;
}
// Put the character from the tail position of the buffer into 'data' and increment the tail index
*data = uart_tx_circBuff.buffer[uart_tx_circBuff.tail++];
uart_tx_circBuff.tail &= (UART_TX_BUF_SIZE - 1); // don't use &= if the buffer size isn't a power of 2
// mark the buffer as full if the head and tail indices are the same
uart_tx_circBuff.isEmpty = (uart_tx_circBuff.head == uart_tx_circBuff.tail);
uart_tx_circBuff.isFull = 0;
// OK
return 1;
}
I'm working on a project with arduino UNO, i'm using freertos for multitasking, i have two tasks :
1-TaskLedBlink.
and 2-TaskSerialP6008.
the first task is used to flash a led twice every given period of time and
the second one is used to receive a frame from serial port and then send it back. the frame should start with 0x02 and ends with 0x0D. when the 0x02 is received, i start adding incoming bytes to an array called asciiFrame until 0x0D was received, after that i send the hole frame back. Until that moment the program was working just fine. then i decided to add a block of code wich is responsible for decoding the asciiFrame, the result is saved in an array called binaryFrame. Here the program's started to act strange . the led stops flashing, sometimes is on sometimes is off, serial data are lost (not received). in the worst cases the program is no more responding until i reboot the arduino.
When i started looking around to solve the problem i found that when i remove this line binaryFrame[m]=(asciiFrame[k]&15)+((asciiFrame[k+1]&15)<<4); the program works fine. Help please solve this problem...here is the code
#include <Arduino_FreeRTOS.h>
#include <semphr.h> // add the FreeRTOS functions for Semaphores (or Flags).
byte inByte = 0; // incoming serial byte
bool startByte = false;
byte asciiFrame[18]; //array to save ascci frame p6008 02 xx xx....0d max 18 bytes including 0x02 and 0x0D
byte binaryFrame[8]; //array to save binary frame p6008 (max 7 bytes + CHECKSUM)
byte i=0; //index used to select case in array
byte j=0; //index used to select byte in array to send it over serial
byte k=0; //index used to convert from ascii to binary
byte m=0; //to save data in binary frame
bool asciiFrameComplete = false; //to indicate that a complete frame(ascii mode) hs been recieved
bool binaryFrameComplete = false;
bool asciiP6008Enabled = true; //true(ascii mode) false(binary mode)
// Declare a mutex Semaphore Handle which we will use to manage the Serial Port.
// It will be used to ensure only only one Task is accessing this resource at any time.
SemaphoreHandle_t xSerialSemaphore;
// define two Tasks for DigitalRead & AnalogRead
void TaskLedBlink( void *pvParameters );
void TaskSerialP6008( void *pvParameters );
// the setup function runs once when you press reset or power the board
void setup() {
// initialize serial communication at 9600 bits per second:
pinMode(13, OUTPUT);
Serial.begin(9600);
// Semaphores are useful to stop a Task proceeding, where it should be paused to wait,
// because it is sharing a resource, such as the Serial port.
// Semaphores should only be used whilst the scheduler is running, but we can set it up here.
if ( xSerialSemaphore == NULL ) // Check to confirm that the Serial Semaphore has not already been created.
{
xSerialSemaphore = xSemaphoreCreateMutex(); // Create a mutex semaphore we will use to manage the Serial Port
if ( ( xSerialSemaphore ) != NULL )
xSemaphoreGive( ( xSerialSemaphore ) ); // Make the Serial Port available for use, by "Giving" the Semaphore.
}
// Now set up two Tasks to run independently.
xTaskCreate(
TaskLedBlink
, (const portCHAR *)"LedBlink" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 1 being the highest, and 4 being the lowest.
, NULL );
xTaskCreate(
TaskSerialP6008
, (const portCHAR *) "AnalogRead"
, 256 // Stack size
, NULL
, 1 // Priority
, NULL );
// Now the Task scheduler, which takes over control of scheduling individual Tasks, is automatically started.
//vTaskStartScheduler();
}
void loop(){
// Empty. Things are done in Tasks.
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
void TaskLedBlink( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
for (;;) // A Task shall never return or exit.
{
digitalWrite(13, HIGH);
vTaskDelay(1);
digitalWrite(13, LOW);
vTaskDelay(6);
digitalWrite(13, HIGH);
vTaskDelay(1);
digitalWrite(13, LOW);
vTaskDelay(17);
}
}
void TaskSerialP6008( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
for (;;)
{
// read the input on analog pin 0:
//int sensorValue = analogRead(A0);
if (Serial.available()>0)
{
inByte = Serial.read();
if ((inByte == 2 || startByte)&&asciiP6008Enabled) //if 2 was received or already has been(startByte), and ascii mode is enabled
{
startByte = true; //start byte came
asciiFrame[i] = inByte; //save bytes in frame array
i++; //increment to the next case in frame array
if (inByte == 13) //end byte came
{
asciiFrameComplete = true;
startByte = false;
i=0;
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
for (j=0;j<18&&asciiFrame[j]!=0;j++) //send frame back
Serial.write(asciiFrame[j]);
memset(asciiFrame, 0, sizeof(asciiFrame)); //then clear it
}
xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
for(k=1 ; k<sizeof(asciiFrame) ; k++)
{
if(asciiFrame[k]==13)
{
binaryFrameComplete=true;
m=0;
break;
}
if(k%2!=0)
{
binaryFrame[m]=(asciiFrame[k]&15)+((asciiFrame[k+1]&15)<<4);
m++;
}
}
// if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
// {
// for (j=0;j<8;j++) //send frame back
// Serial.write(binaryFrame[j]);
// memset(asciiFrame, 0, sizeof(asciiFrame)); //then clear it
// memset(binaryFrame, 0, sizeof(asciiFrame)); //then clear it
// }
// xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}
if (i==sizeof(asciiFrame)) //if array is full ecrase received data, frame length should not exceed 18 bytes
{
memset(asciiFrame, 0, sizeof(asciiFrame)); //clear array
i=0; //init i
startByte = false;
}
}
else if(!asciiP6008Enabled) //binary enabled
{
Serial.println("binary enabled");
}
}
//vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}
I think the problem was declaring the variables as global, i've declared them inside the task and it's working pretty good.
seems you're near the RAM limits...
or your m exceeds the binaryFrame limits...
By quickly looking, I estimate m being about half of k, and you defined
byte asciiFrame[18];
byte binaryFrame[8];
and if there's no 0x0D, you won't reset m ...
With local variables you get a different behavior when spoofing memory.
I am using an MSP430 and writing code in C. I am receiving characters (working) via UART and placing them into an array rxDataArray. Since I am using an MSP430G2211, I have limited memory. The maximum array size is 50 and any more it won't build/load and says out of space.
My MSP430 is communicating to a ESP8266 module (wifi) where I am using "AT" commands. I am receive an echo of my AT command, followed by a response (ex. AT+RST responds with AT+RST...ok). I am confused using C, how I can make a string with just the "ok" response and check if it worked correctly. I have the data in the array, just not sure how to pick certain elements of the array, make a string, and compare that to "ok" response. I am used to using CString in C++ and am confused how to do this in C.
/--------------------------------------------------------------------
// Timer_A UART - Receive Interrupt Handler
//-------------------------------------------------------------------
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMERA1_VECTOR
__interrupt void Timer_A1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMERA1_VECTOR))) Timer_A1_ISR (void)
#else
#error Compiler not supported!
#endif
{
static unsigned char rxBitCnt = 8;
static unsigned char rxData = 0;
switch (__even_in_range(TAIV, TAIV_TAIFG)) { // Use calculated branching
case TAIV_TACCR1: // TACCR1 CCIFG - UART RX
TACCR1 += UART_TBIT; // Add Offset to CCRx
if (TACCTL1 & CAP) { // Capture mode = start bit edge
TACCTL1 &= ~CAP; // Switch capture to compare mode
TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0
}
else {
rxData >>= 1;
if (TACCTL1 & SCCI) { // Get bit waiting in receive latch
rxData |= 0x80;
}
rxBitCnt--;
if (rxBitCnt == 0) { // All bits RXed?
rxBuffer = rxData; // Store in global variable
if (rxDataCnt < 50)
{
rxDataArray[rxDataCnt] = rxBuffer;
rxDataCnt++;
}
else
{
int i = 0;
for (i; i<50-1; i++)
{
rxDataArray[i] = rxDataArray[i+1];
}
rxDataArray[50-1] = rxBuffer;
}
rxBitCnt = 8; // Re-load bit counter
TACCTL1 |= CAP; // Switch compare to capture mode
__bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR)
}
}
break;
}
}
//-----------------------------------------------------------------------
You can turn OFF echo by sending ATE0 command.
Also to find the intended string response please follow below steps:
Enable UART Transmit and Receive Interrupt.
After completing your command transmission you will start receiving data in UART ISR.
In the receive interrupt start a timer of say 1 second(You need to consider baud-rate for exact calculation).
Make track of number of received bytes in UART ISR.
Now after timer expires add null to end of last received byte in buffer.
Now,You can use string manipulation functions of C to find the intended response.
I am trying to write a device code for C8051F340 to get the data from the host(PC) via USB. I have some example from silicon lab and the code look like below:
void Receive_File(void)
{
ReadStageLength = ((BytesToRead - BytesRead) > MAX_BLOCK_SIZE_READ)? MAX_BLOCK_SIZE_READ:(BytesToRead - BytesRead);
BytesRead += Block_Read((U8*)(&TempStorage[BlockIndex]), ReadStageLength); // Read Block
BlockIndex++;
// If device has received as many bytes as fit on one FLASH page, disable interrupts,
// write page to flash, reset packet index, enable interrupts
// Send handshake packet 0xFF to host after FLASH write
if ((BlockIndex == (BLOCKS_PR_PAGE)) || (BytesRead == BytesToRead))
{
Page_Erase((U8*)(PageIndices[PageIndex]));
Page_Write((U8*)(PageIndices[PageIndex]));
PageIndex++;
Led1 = !Led1;
BlockIndex = 0;
Buffer[0] = 0xFF;
Block_Write(Buffer, 1); // Send handshake Acknowledge to host
}
// Go to Idle state if last packet has been received
if (BytesRead == BytesToRead) {M_State = ST_IDLE_DEV; Led1 = 0;}
}
// Startup code for SDCC to disablt WDT before initializing variables so that
// a reset does not occur
#if defined SDCC
void _sdcc_external_startup (void)
{
PCA0MD &= ~0x40; // Disable Watchdog timer
}
#endif
I have some questions want to ask:
1. Where the data goes? the Buffer [0]?
2. if I got a Hex value transfer from the host, can I just read the Buffer [0] to get it ?
sorry I am a newbie.
Thank you.
Your received data stored in array TempStorage
You used Buufer[0] (the value 0xFF) for to send data to host
Here is my code for writing a 512byte block into an SD card. The code works fine, but when I check that everything went good (by reading the response by SD), I read 0xFF.
That values should be something like (from SD reference manual):
‘010’—Data accepted.
‘101’—Data rejected due to a CRC error.
‘110’—Data rejected due to a Write Error
This is the code:
uint8_t SdCard_SendBlock(uint32_t block, uint8_t * data)
{
switch (sd_write_blk_machine.fields.state)
{
case WRITE_START:
//Enable Card
GPIOC_PDOR &= ~GPIO_PDOR_PDO(GPIO_PIN(10));
sd_cmd_arg.sd_cmd_tot_argument = block << SD_BLOCK_SHIFT;
sd_write_blk_machine.fields.state = WRITE_SEND_CMD24;
/*INIZIALIZZO LE VARIABILI LOCALI*/
write_send_data_counter = 0;
sd_cmd_machine.sd_cmd_machine = 0;
break;
case WRITE_SEND_CMD24:
send_command_return = SdSendCmd(CMD24|0x40,ASPECTED_OK_RESPONSE);
if( send_command_return == SDCARD_CMD_FAILS)
{
//Disable Card
GPIOC_PDOR |= GPIO_PDOR_PDO(GPIO_PIN(10));
sd_write_blk_machine.fields.complete = 1;
system_error.flags.sdcard_error = SDCARD_WRITE_FAIL;
return(SDCARD_WRITE_FAIL);
}
sd_write_blk_machine.fields.state = WRITE_SEND_START_TOKEN;
}
break;
case WRITE_SEND_START_TOKEN:
Spi_writeData(SPI0,SD_TOK_WRITE_SBLOCK); //SD_TOK_WRITE_SBLOCK = 0xFE ,
spi_control_machine.spi_control_machine = 0;
sd_write_blk_machine.fields.state = WRITE_SEND_DATA;
break;
case WRITE_SEND_DATA:
if (write_send_data_counter < SDCARD_BLOCK_SIZE) //SDCARD_BLOCK_SIZE = 512 byte
{
Spi_writeData(SPI0, data[write_send_data_counter]);
{
spi_control_machine.spi_control_machine = 0;
write_send_data_counter++;
}
}
else
sd_write_blk_machine.fields.state = WRITE_SEND_IDLE_1;
break;
case WRITE_SEND_IDLE_1:
Spi_writeData(SPI0,0xFF); // 0xFF = SPI_IDLE
sd_write_blk_machine.fields.state = WRITE_SEND_IDLE_2;
break;
case WRITE_SEND_IDLE_2:
Spi_writeData(SPI0,0xFF); // 0xFF = SPI_IDLE
sd_write_blk_machine.fields.state = WRITE_READ_RESPONSE_TOKEN;
break;
case WRITE_READ_RESPONSE_TOKEN:
/*Every data block written to the card will be acknowledged by a data response token. It is one byte long
and has the following format:
x x x 0 Status 1
The meaning of the status bits is defined as follows:
010 - Data accepted.
101 - Data rejected due to a CRC error.
110 - Data Rejected due to a Write Error*/
spi_control_machine.spi_control_machine = 0;
Spi_readData(SPI0, &write_read_response); // HERE IS THE PROBLEM !!!! write_read_response = 0xFF
if ( (write_read_response & 0x0F) != SD_ACCEPTED_WRITE_DATA )
{
//disabilita carta
GPIOC_PDOR |= GPIO_PDOR_PDO(GPIO_PIN(10));
system_error.flags.sdcard_error = SDCARD_WRITE_FAIL;
sd_write_blk_machine.fields.complete = 1;
SendBlockReturn=0;
return (SDCARD_WRITE_FAIL);
}
sd_write_blk_machine.fields.complete = 1;
status.flags.sdwrite_wait_attemp = 1;
SendBlockReturn=1;
return (TERMINATE_OK);
break;
}
The issue is in the last case of the switch.
It looks like the card is returning 0xFF until it has completed the write. According to the Physical Layer Simplified Specification in section 7.2.4:
As long as the card is busy programming, a continuous stream of busy tokens will be sent to the host (Effectively holding the DataOut line low).
That said, I'm not sure why the card isn't returning the '010' accepted response first - it could be a case of the card manufacturer not following the spec.
What you want to do is repeatedly call Spi_readData until it the returned byte becomes 0 or '010' accepted.
If you look at the diagrams on the SD specification the busy tokens come after the data response, what you're seeing is normal, after you send the last byte you should keep reading data until you get the data response token, then the card will start programming and you'll get the busy tokens until the programming completes. When the card is programming you'll read 0's (data line is held LOW). After you transfer the last byte I don't think the spec says what the state of the data line will be, I always get 0xFF too but you should not count on it so just keep checking for the response token until you get it.