Write a block to SD with SPI, strange response from SD - c

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.

Related

how to read report id in the first byte from hid data for the hid device?

I am using ftdi chip VNC2 and scan data using two barcode readers, however, one receives 8-byte data and the other receives 9-byte data. And I use wireshark to check the package they received, then I found that the 9-byte-barcode reader had one more byte (here the report id is 0x03) before the other 8-byte barcode reader. And the one more byte is report id that I found in wireshark capture.
However, I tried to get the report descriptor by sending request from USB host (i.e. VNC2), however I got different information (they are (desc_dev.wValue >> 8) & 0xff = 0x5F; desc_dev.wValue & 0xff = 0x73;).
My question is how could I get the correct report id (i.e., 0x03)? could anyone give me some suggestions? Thank you so much!
This is the code requesting for "GET_DESCRIPTOR" code value modified from example code of VNC2.
// host controller device descriptor
usb_deviceRequest_t desc_dev;
// user ioctl to find control endpoint on this device
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_GET_CONTROL_ENDPOINT_HANDLE;
hc_iocb.handle.dif = ifDev;
hc_iocb.get = &epCtrl;
status = vos_dev_ioctl(hUSBHOST_1, &hc_iocb);
if (status != USBHOST_OK) {
break;
}
desc_dev.bmRequestType = USB_BMREQUESTTYPE_HOST_TO_DEV | USB_BMREQUESTTYPE_CLASS | USB_BMREQUESTTYPE_DEVICE;
desc_dev.bRequest = 0x06; // 0x06 means GET_DESCRIPTOR
hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_SETUP_TRANSFER;
hc_iocb.handle.ep = epCtrl;
hc_iocb.set = &desc_dev;
status = vos_dev_ioctl(hUSBHOST_1, &hc_iocb);
if (status != USBHOST_OK) {
break;
}
hid_reportid_2 = desc_dev.wValue & 0xff;
hid_reportid_3 = (desc_dev.wValue >> 8) & 0xff;
This is the code to get report descriptor modified from example code for hid device of VNC2.
hid_iocb.descriptorType = USB_DESCRIPTOR_TYPE_REPORT;
hid_iocb.descriptorIndex = USB_HID_DESCRIPTOR_INDEX_ZERO;
hid_iocb.Length = 0x40;
hid_iocb.get.data = &transfer_buf[0];
hid_iocb.ioctl_code = VOS_IOCTL_USBHOSTHID_GET_DESCRIPTOR;
status = vos_dev_ioctl(hUSBHOST_HID, &hid_iocb);
if (status != USBHOSTHID_OK)
{
break;
}
hid_protocoltype = hid_iocb.protocolType;
hid_reporttype = hid_iocb.reportType;
hid_reportid = hid_iocb.reportID;
From the code above, hid_protocoltype = 0x6F; hid_reporttype = 0x73; hid_reportid = 0x5F; hid_reportid_2 = 0x00; hid_reportid_3 = 0x00.
Any suggestions are appreciated.

Microchip PIC24FJ SPI writes correctly but only reads zeros

I have a PIC24FJ256GA702 communicating with a AD5724RBREZ quad DAC with a SPI link.
The DAC works fine, writing is no problem, but I am stuck on reading back the control register from it.
I get the correct waveform on the PIC pin that I am expecting, and the read routine runs, but it always returns zeros. The waveform is clearly not zero- the waveform on the scope is correct for the 4 channels and the internal reference being enabled.
Scope view of waveforms - blue = clock, yellow = data input from DAC at PIC pin
(The excessive ringing on the scope image is probably caused by a long distance ground connection- in practice these chips are about 25mm apart.)
I thought that the input pin was configured as an analogue, but it was correctly a digital input.
I connected it to a counter based on Timer1, and that counter does count if I try to read the DAC. This suggests that the PPS is working, the pin is not bust, and the the input signal is clean enough to use.
I think it may be a problem with the code or the decode timing of the SPI module, but as shown in the image the data is stable during the clock cycle so I cannot see what is wrong.
I have searched the forums, and it seems most with this problem trace it to analogue functions being enabled but that is not the case here.
Would anyone like to suggest something else to try, or post some working SPI read code if my code is not looking correct?
The code follows-
void AOUT_init(void)
{
//assume PPS is unlocked (it is on reset) - see note below
//setup SPI1 itself
SPI1CON1L = 0x0160; //TX work read 0
//SPI1CON1L = 0x0060; //TX not work
//SPI1CON1L = 0x0120; //TX work, read 0
//SPI1CON1L = 0x0020; //not tried
SPI1CON1H = 0x3000;
SPI1CON2L = 0x0017; //word length (17 hex = 24 bits)
//BRG
SPI1BRGL = 0x0000; //default = no divisor
//PPS - assume unlocked at this point
ANSBbits.ANSB13 = 0;
TRISBbits.TRISB13 = TRIS_INPUT;
//##########################################################################
RPINR20bits.SDI1R = 13; //set SDI1 data input to PIC to RB13
//##########################################################################
TRISBbits.TRISB15 = TRIS_OUTPUT;
RPOR7bits.RP15R = 8; //RB15 to SDI1 clock out from PIC
TRISBbits.TRISB14 = TRIS_OUTPUT;
RPOR7bits.RP14R = 7; //RB14 to SDI1 data out from PIC
//AD5724R has additional lines - not all used in practice
//setup and set initial level here
//AOUT-/LDAC
TRISBbits.TRISB6 = TRIS_OUTPUT;
LATBbits.LATB6 = 1;
//AOUT-/SYNC
TRISBbits.TRISB7 = TRIS_OUTPUT;
LATBbits.LATB7 = 1;
//AOUT-/CLR
TRISBbits.TRISB12 = TRIS_OUTPUT;
LATBbits.LATB12 = 1;
//turn SPI on
SPI1CON1Lbits.SPIEN = 1;
SPI1CON1Lbits.MSTEN = 1; //included in definition above
//now setup the AD chip
//output range set
AOUT_TX(0x0C00,0x0100); //all channels to 10V
//control
AOUT_TX(0x1900,0x0500);
//power control - enable DACs
AOUT_TX(0x1000,0x1F00);
}
The comms routine below is included for completeness- it just controls the other DAC lines. The /SYNC line is doing a chip select function.
static void AOUT_Comms(bool bSync, bool bLDAC, bool bClr)
{
//AOUT-/LDAC
LATBbits.LATB6 = bLDAC;
//AOUT-/SYNC
LATBbits.LATB7 = bSync;
//AOUT-/CLR
LATBbits.LATB12 = bClr;
}
This is write routine which works fine.
void AOUT_TX(uint16_t dataH, uint16_t dataL)
{
//AOUT uses 24 bit data
//this routine handles /SYNC line
//relies on AD chip having much faster response than chip cycle time
//AD chip limits at about 38MHz so much quicker than PIC.
AOUT_Comms(0,1,1);
SPI1BUFL = dataL;
SPI1BUFH = dataH;
while(SPI1STATLbits.SPIBUSY) //wait until sent
{
;
}
AOUT_Comms(1,1,1);
//
}
This is the read routine, which uses the routines above.
void AOUT_read_control(uint16_t ReadH, uint16_t ReadL)
{
uint16_t temp;
//to read, transmit the register to be read, then transmit a dummy command "NOP" to clock the data out.
//send register
AOUT_TX(0x9000,0x0000);
//read out- this is similar to write but reads the received buffer at the end.
//clear buffer
while (SPI1STATLbits.SPIRBF)
{
temp = SPI1BUFL;
temp = SPI1BUFH;
}
AOUT_Comms(0,1,1);
SPI1BUFL = 0;
SPI1BUFH = 0x1800; //nop operation via control register
while(SPI1STATLbits.SPIBUSY) //wait until sent
{
;
}
while (!SPI1STATLbits.SPIRBF)
{
; //hold until something received
}
ReadH = SPI1BUFH;
ReadL = SPI1BUFL; //these read zero
AOUT_Comms(1,1,1);
//
//dummy so can check counter also connected to same pin
temp = TMR1;
temp = TMR1;
}
Update-
I checked the SPI read decode by sending the received words directly to a display as suggested by the comments. I get 0000 for both words.
Also as suggested I connected a logic analyser at the PIC pins, and it decodes both read and write correctly.Logic Analyser view- Ch1/Blue/MOSI writing 0x180000, Ch2/Green/MISP reading 0x00001F, both correct

How can I create a bidirectional bus using a 18F4550?

Basically what Im trying to do its to use a single port of the PIC18F4550 as both inputs and outputs. Im going to connect a 7-segment-display to 7 pins of the port and with 4 pins of the same port. The four inputs are for introduce the numbers from 0 to 15 (F) in binary and the number in binary will represent in decimal in the display. Im using PIC C Compiler for the code.
Update: Following the first comment I modify the code and I think it is basically the same, I just read directly the input of the port B and use a switch-case in order to send the corresponding decimal number, also I added a default state so when I connected it should be a 0 in the display. Here it is the connection diagram, my teacher told me that I can ignore the logic gates but I'm not shure about that, in case I want to added I just need to use another port like port D to send a single high or low depending on how the port B is working.
Update 2: It finally work, it seems that the fact that I can ignore the logic gates it was partially true, the code was easier than I though, I just added a three port D high and low outputs to the EN and OE of both 74Ls244 and 74HC573 corresponding inputs so I can enable or disable depending on the port B state (output or input). Thank you all.
#include<18F4550.h>
#fuses XT, NOWDT, NOLVP, NOPROTECT, PUT
#use delay(clock = 4M, crystal = 8M)
#use fast_io(b)
void main(){
int8 INDSP;
int8 OUTDSP;
while(true){
SET_TRIS_B(0xFF);
INDSP = input_b()&0x0F;
switch(INDSP){
case 0b00000000:
OUTDSP = 0x3F;
break;
case 0b00000001:
OUTDSP = 0x0C;
break;
case 0b00000010:
OUTDSP = 0x76;
break;
case 0b00000011:
OUTDSP = 0x5E;
break;
case 0b00000100:
OUTDSP = 0x4D;
break;
case 0b00000101:
OUTDSP = 0x5B;
break;
case 0b00000110:
OUTDSP = 0x7B;
break;
case 0b00000111:
OUTDSP = 0x0E;
break;
case 0b00001000:
OUTDSP = 0x7F;
break;
case 0b00001001:
OUTDSP = 0x4F;
break;
case 0b00001010:
OUTDSP = 0x6F;
break;
case 0b00001011:
OUTDSP = 0x79;
break;
case 0b00001100:
OUTDSP = 0x33;
break;
case 0b00001101:
OUTDSP = 0x7C;
break;
case 0b00001110:
OUTDSP = 0x73;
break;
case 0b00001111:
OUTDSP = 0x63;
break;
DEFAULT:
OUTDSP = 0x3F;
break;
}
delay_ms(500);
SET_TRIS_B(0x00);
output_b(OUTDSP);
delay_ms(500);
}
}
Caveat: Not a total solution, but some suggestions ...
We can simplify your main as it has large amounts of replicated code:
void
main()
{
SET_TRIS_B(0b00001111);
DSPIN = input_b();
while (true) {
if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
DSPOUT = DSPIN;
else
DSPOUT = 0;
delay_ms(1000);
SET_TRIS_B(0b11111111);
if ((DSPOUT >= 0) && (DSPOUT <= 15))
output_b(DSPVALOR[DSPOUT]);
else
output_b(DSPVALOR[0]);
delay_ms(1000);
}
}
Now, given the top part of main:
SET_TRIS_B(0b00001111);
DSPIN = input_b();
The question I have is: should this be inside the while loop at the top???
Otherwise, there's no need for a loop as DSPIN and DSPOUT will remain constant.
UPDATE:
This is a total guess, but after cursorily looking at the datasheet ...
I think you're mixing up the value for the TRIS port. The second set_tris_b call should have 0b00000000 to set all bits for output (and not 0b11111111 as you have which sets all bits for input).
I'm not sure you can do this with a single 8 bit port. You need four bits for the input value. But, you need seven bits for output to the 7 segment display.
This adds up to more than 8 bits. So, I think you need two ports. Since you're using port "b", I presume there is a port "a".
You may be able to time division multiplex a given bit for input and output as you've done, but I think it's dicey and I don't know enough about the specifics of the 18F's ports to say for sure.
Here's refactored code that assumes a separate port "a":
void
main()
{
while (true) {
// set port B lower four bits for input
SET_TRIS_B(0b00001111);
// get input and mask off don't care bits
DSPIN = input_b();
DSPIN &= 0b00001111;
if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
DSPOUT = DSPIN;
else
DSPOUT = 0;
delay_ms(1000);
// set port A pins for output
SET_TRIS_A(0b00000000);
if ((DSPOUT >= 0) && (DSPOUT <= 15))
output_a(DSPVALOR[DSPOUT]);
else
output_a(DSPVALOR[0]);
delay_ms(1000);
}
}
But, if the 18F lets you change the tristate bits on the fly and you can connect both the input bit switches on bits 0-3 and the 7 segment output bits on bits 0-6, you can simply change all *_a calls into *_b calls.
UPDATE #2:
Upon further reflection [and, again, this is speculation], if the 18F allows one port to be switched back and forth repeatedly between input and output, the "duty cycle" in the above code is [probably] incorrect.
With 1000ms for both delays, the duty cycle is [only] 50% for output, so the 7 segment display will probably flicker badly.
That's because, when in tristate/input mode, the 7 segment display is not being driven with the correct segment mask/output value
The solution is to increase the duty cycle to (e.g.) 99.44% [the purity of Ivory Soap :-)]. So, most of the time, the port is in output mode. We only enter tristate/input mode briefly to sample the [DIP switch] input pins.
Here's a refactored version that keeps the port in output mode a high percentage of the time:
// NOTE: these may be need to be adjusted
enum {
INPUT_STABILIZE_DELAY = 1, // as short as possible
OUTPUT_STABILIZE_DELAY = 1, // as short as possible
OUTPUT_HOLD_DELAY = 100, // as long as possible
};
void
main()
{
while (true) {
// set port B lower four bits for input
SET_TRIS_B(0b00001111);
// allow port to stabilize
delay_ms(INPUT_STABILIZE_DELAY);
// get input and mask off don't care bits
DSPIN = input_b();
DSPIN &= 0b00001111;
// set output mode based on input
if ((DSPIN >= 0b00000000) && (DSPIN <= 0b00001111))
DSPOUT = DSPIN;
else
DSPOUT = 0;
// set port B pins for output
SET_TRIS_B(0b00000000);
// allow tristate pins to stabilize
delay_ms(OUTPUT_STABILIZE_DELAY);
// output to 7 segment delay
output_b(DSPVALOR[DSPOUT]);
// ensure that port is in output mode 99.44% of the time
delay_ms(OUTPUT_HOLD_DELAY);
}
}

TM4C123G6PMI USB Device Communication

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

PIC18F25K80 sending string through USART not working

I'm programming a few libraries for a board with a PIC18F25K80 built-in. Right now I'm trying to program the UART library and I've tried everything but I cannot make it work when it comes to send a string of chars.
I'm using the XC8 compiler and I have the following code in the library: (I haven't programmed the interruptions yet, that's why you can't see anything related to that in the code.
void UARTsend(char data){
UARTbusy();
TXREG1 = data;
}
void UARTsendTEXT(unsigned char *text){
while(*text != '\0'){
UARTsend(*(text++));
}
}
char UARTbusy(){
return TXSTA1bits.TRMT;
}
And this code in the main file:
int main() {
UARTconfig(_BR_19200, _RxINT_OFF, _TxINT_OFF, _8BIT);
unsigned char data[20] = "ABCDEFGHIJ";
while(1){
if(UARTrxREAD() == 'a'){
UARTsendTEXT(data);
}
}
return 0;
}
So, when I hit 'a', the string should be sent but instead of seeing the string, I receive the first and last letter, and sometimes just the first letter.
Honestly, I believe it is a really basic problem with the code, but I tried everything I could think about and nothing worked, so maybe someone here can help me with that.
EDIT: just in case you need to check it out:
void UARTconfig(unsigned int BaudRate, unsigned int RxINT, unsigned int TxINT, unsigned int BIT){
int br_data;
//Clock configuration at 16MHz
OSCCONbits.IRCF = 0b111;
//9-bit transmit enable bit.
if(BIT == 1) {
RCSTA1bits.RX9 = 1; //Reception 9-bit.
TXSTA1bits.TX9 = 1; //Transmission 9-bit.
}
else {
RCSTA1bits.RX9 = 0; //Reception 8-bit.
TXSTA1bits.TX9 = 0; //Transmission 8-bit.
}
//Enable serial port.
RCSTA1bits.SPEN = 1;
//Enable continuous reception.
RCSTA1bits.CREN = 1;
//Setting asynchronous mode.
TXSTA1bits.SYNC = 0;
//Enable transmission
TXSTA1bits.TXEN = 1;
//Setting Rx/Tx pins as output.
TRISC7 = 0;
TRISC6 = 0;
//Baud rate configuration
BAUDCON1bits.BRG16 = 1; //16bit Baud Rate generator
TXSTA1bits.BRGH = 0; //Low speed BR.
switch(BaudRate){
case 0:
br_data=415;
break;
case 1:
br_data=103;
break;
case 2:
br_data=51;
break;
case 3:
br_data=16;
break;
case 4:
br_data=8;
}
SPBRGH1:SPBRG1 = br_data;
}
The function UARTbusy should be waiting for status, or its caller should be. But the transmit register status is read once and ignored.
There is typically a two-stage buffer for transmitted data. Values written to the interface register are held until the shift register is empty, and the device remains 'busy' until then.
When you write the first data, it is transferred immediately to the shift register, so writing the second data immediately is harmless. But you then keep on over-writing the contents of the output register until it holds the last character of your message. Then when the shift register becomes empty, the last character of your message is sent.
Remember that the shift register is shifting bits out relatively slowly - at the baud rate. That is why the status bit needs to be checked.

Resources