Why HM-10 doesn't send an OK if i send AT from an MSP430 Launchpad? - embedded

I'm trying to set up an UART communication with a HM-10 chip on a Texas Instruments MSP430 Launchpad, but I ran into a very elementary problem.
What I want to achieve is to send an "AT" through UART to HM-10, and receive an answer for that. By the way this is a code I found here and I slightly modified for my purposes.
#include "msp430g2553.h"
const char string[] = { "AT" };
unsigned int i;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog
//------------------- Configure the Clocks -------------------//
if (CALBC1_1MHZ==0xFF) // If calibration constant erased
{
while(1); // do not load, trap CPU!!
}
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
//---------------- Configuring the LED's ----------------------//
P1DIR |= BIT0 + BIT6; // P1.0 and P1.6 output
P1OUT &= ~BIT0 + BIT6; // P1.0 and P1.6 = 0
//--------- Setting the UART function for P1.1 & P1.2 --------//
P1SEL |= BIT1 + BIT2; // P1.1 UCA0RXD input
P1SEL2 |= BIT1 + BIT2; // P1.2 UCA0TXD output
//------------ Configuring the UART(USCI_A0) ----------------//
UCA0CTL1 |= UCSSEL_2 + UCSWRST; // USCI Clock = SMCLK,USCI_A0 disabled
UCA0BR0 = 104; // 104 From datasheet table-
UCA0BR1 = 0; // -selects baudrate =9600,clk = SMCLK
UCA0MCTL = UCBRS_1; // Modulation value = 1 from datasheet
//UCA0STAT |= UCLISTEN; // loop back mode enabled
UCA0CTL1 &= ~UCSWRST; // Clear UCSWRST to enable USCI_A0
//---------------- Enabling the interrupts ------------------//
IE2 |= UCA0TXIE; // Enable the Transmit interrupt
IE2 |= UCA0RXIE; // Enable the Receive interrupt
_BIS_SR(GIE); // Enable the global interrupt
i = 0;
UCA0TXBUF = string[i]; // Transmit a byte
_BIS_SR(LPM0_bits + GIE); // Going to LPM0
}
//-----------------------------------------------------------------------//
// Transmit and Receive interrupts //
//-----------------------------------------------------------------------//
#pragma vector = USCIAB0TX_VECTOR
__interrupt void TransmitInterrupt(void)
{
P1OUT ^= BIT0;//light up P1.0 Led on Tx
if (i == sizeof string - 1)
{
UC0IE &= ~UCA0TXIE;
}
UCA0TXBUF = string[i++];
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void ReceiveInterrupt(void)
{
// light up P1.6 LED on RX
if (UCA0RXBUF == 'O')
{
P1OUT ^= BIT6;
}
IFG2 &= ~UCA0RXIFG; // Clear RX flag
}
According to the datasheet I should receive an OK answer for this command.
If there was an 'O' in the RX buffer, I would expect the LED to light up on my board, but that doesn't happen.
Using Code Composer, I also verified with adding a breakpoint to the RX interrupt that there is indeed no RX answer.
I believe this is entirely a software question, that's why I put it here. I'm using the correct rotation of jumpers(http://xanthium.in/Serial-Communication-MSP430-UART-USCI_A) and RX is wired to TX and vica versa.
I would appreciate if you could point out if I was doing anything conceptionally wrong or if I just made a mistake. Thank you!

I see a problem in the interrupt routine TransmitInterrupt(): you should use UCA0TXBUF = string[++i]; because using "i++" you transmit two times the letter "A". The test about sizeof(string) should also be retouched.
Then, I would not trust too much the datasheet. I think that, despite what the datasheet says, every command sent to the modem must be terminated by CR (\r), otherwise how could the modem discern an "AT" from an "AT+RESET"? I am not really sure but the datasheet doesn't seem a high quality one. Anyway, it's a quick test (to add a \r to the end of the string).
Finally, the CTS and RTS signals can play a role too. Some modem wants RTS asserted, other modems don't care, and terminology sometimes is confusing: when datasheet says RTS, does it mean RTS of the modem or RTS of the host? I hope this helps, you should do a few scientific tries.

I think for everyone who is working with HM-10 devices in the future I want to answer this question, because it has I think its own sort of mini-literature, which was first frustrating, but then I kind of liked the challenges it posed to me.
Some of the problems are hardware related, so this post might need to be moved to an embedded engineering section. (Great consequence - you cannot be 100% sure before checking it with a scope)
Know your hardware - HM-10 has tons of versions, and it turned our one needed an extra potential divider because it has a 3.3V logic level high instead of 5V. This website is a fantastic place to start. Though, ours turned out to be an MLT-BT05 which is a clone of a clone. It doesn't have iBeacon capability on its firmware, so if you don't want to power cycling, then you should probably avoid this one.
About the coding bit the most important thing is to check with \n, \r and \n\r, as linuxfan briefly mentioned its importance above, because some of the devices need it. The best place to start is AT and if it works, then use AT+HELP and find the version, usually AT+VERSION command so you can identify with 100% certainty which chip you have.
Currenetly it is prototyped on an Arduino, but I will include working code as soon as its finished on MSP430.
The Arduino code:
#include <SoftwareSerial.h>
SoftwareSerial bluetooth(9, 10); // RX, TX
char commandbuffer[50];
int j = 0;
void setup()
{
memset(commandbuffer, 0, sizeof(commandbuffer));
analogWrite(12, 255);
analogWrite(11, 0);
// Start the hardware serial port
Serial.begin(19200);
bluetooth.begin(9600);
// un REM this to set up a Master and connect to a Slave
Serial.println("BLE CC41A Bluetooth");
Serial.println("----------------------------------");
Serial.println("");
Serial.println("Trying to connect to Slave Bluetooth");
delay(1000);
bluetooth.println("AT"); // just a check
delay(2000);
bluetooth.println("AT+NAMEHIST");
delay(2000);
bluetooth.println("AT+ROLE0");
delay(2000);
bluetooth.println("AT+INQ"); // look for nearby Slave
delay(5000);
bluetooth.println("AT+CONN1"); // connect to it */
}
void loop()
{
bluetooth.listen();
// while there is data coming in, read it
// and send to the hardware serial port:
while (bluetooth.available() > 0) {
char inByte = bluetooth.read();
Serial.write(inByte);
}
// Read user input if available.
if (Serial.available()) {
delay(10); // The DELAY!
char temp = Serial.read();
if (temp == '\n')
{
bluetooth.println(commandbuffer);
Serial.println(commandbuffer);
memset(commandbuffer, 0, sizeof(commandbuffer));
j = 0; // Reset
}
else
{
commandbuffer[j++] = temp;
}
delay(500);
}

Related

UART Serial Bridge using MSP430 FR5994

I am trying to create a UART bridge using MSP430. I have a sensor sending strings to the MSP430 which I intend to send to my PC. Additionally, the sensor responds to commands which I intend to send using my PC through the MSP430 bridge. The commands I am sending to the sensor reach it without any flaw. However, the messages sent by the sensor reach the TXBUF of the UART connected to my PC but does not appear on the terminal. On checking the registers I see 0x000A on the TXBUF but it appears to recieve all the chahracters. But nothing is printed.
I am using the following code:
#include <msp430.h>
unsigned char *msg;
unsigned char i=0 , j=0;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer
// Pin Initialization
P6SEL1 |= BIT1;
P6SEL0 &= ~BIT1;
P6SEL1 |= BIT0;
P6SEL0 &= ~BIT0;
P2SEL1 |= BIT5;
P2SEL0 &= ~BIT5;
P2SEL1 |= BIT6;
P2SEL0 &= ~BIT6;
PM5CTL0 &= ~LOCKLPM5;
// UART Initialization
UCA1CTLW0 |= UCSWRST;
UCA1CTLW0 |= UCSSEL__SMCLK; // Using 1 MHZ clock
UCA3CTLW0 |= UCSWRST;
UCA3CTLW0 |= UCSSEL__SMCLK;
UCA3BRW = 6; // Baud Rate set to 9600
UCA3MCTLW = UCOS16 | UCBRF_8 | 0x2000;
UCA1BRW = 6;
UCA1MCTLW = UCOS16 | UCBRF_8 | 0x2000;
UCA3CTLW0 &= ~UCSWRST;
UCA1CTLW0 &= ~UCSWRST;
UCA3IE |= UCRXIE;
UCA1IE |= UCRXIE;
__enable_interrupt(); // Interrupt enable
while (1)
{}
}
// UART A3 connected to the PC.
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=EUSCI_A3_VECTOR
__interrupt void USCI_A3_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(EUSCI_A3_VECTOR))) USCI_A3_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA3IV, USCI_UART_UCTXCPTIFG))
{
case USCI_NONE: break;
case USCI_UART_UCRXIFG:
while(!(UCA3IFG&UCTXIFG));
UCA1TXBUF = UCA3RXBUF;
__no_operation();
break;
case USCI_UART_UCTXIFG: break;
case USCI_UART_UCSTTIFG: break;
case USCI_UART_UCTXCPTIFG: break;
default: break;
}
}
// UART A1 connected to the sensor.
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=EUSCI_A1_VECTOR
__interrupt void USCI_A1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(EUSCI_A1_VECTOR))) USCI_A1_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG))
{
case USCI_NONE: break;
case USCI_UART_UCRXIFG:
while(!(UCA1IFG&UCTXIFG)); //Trying to read a string
{
*(msg+i) = UCA1RXBUF;
j = *(msg+i);
UCA3TXBUF = j;
i++;
}
break;
case USCI_UART_UCTXIFG: break;
case USCI_UART_UCSTTIFG: break;
case USCI_UART_UCTXCPTIFG: break;
default: break;
}
}
Please help.
Thanks in advance.
First, the problems that I see with your listing:
(p1) Even though the baud rates of both UARTs are the same, your design does not make use of proper (see problem 3 below) buffering in the event that both the PC and the sensor is sending data at the same time. To make matters worse, both your ISRs contain blocking while loops that don't buffer and only waste time until the interrupt flags clears.
(p2) Your source (shown below) is likely coded in error:
while(!(UCA1IFG&UCTXIFG)); //Trying to read a string
{
*(msg+i) = UCA1RXBUF;
j = *(msg+i);
UCA3TXBUF = j;
i++;
}
because the body of the while loop is actually empty due to the trailing ";" so the code within the open/closing brackets that follows is not part of the while loop.
(p3) The pointer variable msg was never initialized. Most likely it points to random heap memory or unused portion of the stack, so the program doesn't crash right away. Eventually, it would because the variable i is incremented but never decremented, so memory is "one time used" by the sensor ISR.
My suggestions:
(s1) Declare two buffers, one for data arriving from the PC and the other for data arriving from the sensor. Remove the "unsigned char *msg" and replace with something like this:
unsigned char pc_data[256];
unsigned char sensor_data[256];
The size 256 is on purpose to create a poor-mans circular buffer when used with an 8-bit index variable. When the variable reaches 255 and is incremented, it will simply roll back to 0. In this case both i and j as you already declared can be used, but maybe pc_data_index and sensor_data_index would be better understood. You also need two more variables for the size of the buffer, maybe pc_data_count and sensor_data_count. If your procssor cannot afford this much buffer space, then decrease to a modular amount (i.e., 2^BUFSIZE, where BUFSIZE = 32) and use the modular operator when updating the index like this:
pc_data_index = (pc_data_index + 1) % BUFSIZE;
(s2) Change both ISR routines to process both the USCI_UART_UCRXIFG and USCI_UART_UCTXIFG interrupt events. The ISRs should not contain any loops, simply buffer data or write data out from buffer. Here is an example:
switch(__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG))
{
case USCI_NONE: break;
case USCI_UART_UCRXIFG:
// Byte was received from sensor, so buffer it
sensor_data[sensor_data_count++] = UCA1RXBUF;
sensor_data_index = (sensor_data_index + 1) % BUFSIZE;
// Enable the TX interrupts to send the buffered data
UCA1IE |= UCTXIE;
break;
case USCI_UART_UCTXIFG:
// Sensor UART is ready to send next byte
UCA3TXBUF = sensor_data[sensor_data_index];
sensor_data_count--;
// Disable the TX interrupt if no more data to send
if (sensor_data_count == 0) UCA1IE &= ~UCTXIE;
break;

ATMEGA2561 WINC1500 Driver implementation SPI problem

I am trying to implement the WINC1500 MLA Driver to work with the ATMEGA2561 MCU and I have written my driver code and it's stuck on the line "while((SPSR & (1 << SPIF)) == 0);" in the m2mStub_SpiTxRx function.
I have no idea why it's not progressing through. I'm using the jumpstart ImageCraft IDE for this project.
Here's the implementation of it
void m2mStub_SpiTxRx(uint8_t *p_txBuf,
uint16_t txLen,
uint8_t *p_rxBuf,
uint16_t rxLen)
{
uint16_t byteCount;
uint16_t i;
// Calculate the number of clock cycles necessary, this implies a full-duplex SPI.
byteCount = (txLen >= rxLen) ? txLen : rxLen;
DEBUGOUTF("Calculate the number of clock cycles\n");
DEBUGOUTF("byteCount %d", byteCount, "\n");
DEBUGOUTF("txLen %d", txLen, "\n");
DEBUGOUTF("rxLen %d", rxLen, "\n");
// Read / Transmit.
for (i = 0; i < byteCount; ++i)
{
// Wait for transmitter to be ready. (This is causing the entire thing to crash)
while((SPSR & (1 << SPIF)) == 0);
// Transmit.
if (txLen > 0)
{
// Send data from the transmit buffer.
SPDR = (*p_txBuf++);
--txLen;
}
else
{
// No more Tx data to send, just send something to keep clock active.
SPDR = 0x00U;
}
// Wait for transfer to finish.
while((SPSR & (1 << SPIF)) == 0);
// Send dummy data to slave, so we can read something from it.
SPDR = 0x00U;
// Wait for transfer to finish.
while((SPSR & (1 << SPIF)) == 0);
// Read or throw away data from the slave as required.
if (rxLen > 0)
{
*p_rxBuf++ = SPDR;
--rxLen;
}
else
{
// Clear the registers
volatile uint8_t reg_clear = 0U;
reg_clear = SPDR;
(void)reg_clear;
}
}
}
I don't have enough information to say for sure, but my assumption is that your SPI connection is not set up correctly.
In particular, I guess you forgot to set /SS as output, same as this problem or this.
In the datasheet it says:
Master Mode When the SPI is configured as a master (MSTR in SPCR is
set), the user can determine the direction of the SS pin.
If SS is configured as an output, the pin is a general output pin
which does not affect the SPI system. Typically, the pin will be
driving the SS pin of the SPI slave.
If SS is configured as an input, it must be held high to ensure Master
SPI operation. If the SS pin is driven low by peripheral circuitry
when the SPI is configured as a master with the SS pin defined as an
input, the SPI system interprets this as another master selecting the
SPI as a slave and starting to send data to it. To avoid bus
contention, the SPI system takes the following actions:
The MSTR bit in SPCR is cleared and the SPI system becomes a slave. As a result of the SPI becoming a slave, the MOSI and SCK pins become
inputs.
The SPIF flag in SPSR is set, and if the SPI interrupt is enabled, and the I-bit in SREG is set, the interrupt routine will be executed.
Thus, when interrupt-driven SPI transmission is used in master mode,
and there exists a possibility that SS is driven low, the interrupt
should always check that the MSTR bit is still set. If the MSTR bit
has been cleared by a slave select, it must be set by the user to
re-enable SPI master mode.
So, you just need to configure the /SS pin as output and set to high in your init code, this should solve your problem:
DDRB |= (1 << PB0); // Set /SS (PB0) as output
PORTB |= (1 << PB0); // Set /SS (PB0) high

Attiny204 Interrupt Flag Not Being Generated

I'm trying to write a (fairly) basic bit of software for and Attiny204, which handles interrupts when a clock input is pulled high.
When I run the code in the debug simulator in Atmel Studio, and set the clock input high, there is no interrupt flag generated. The interrupts do trigger when I manually produce an interrupt flag.
I've tried using different pins, and even, the other port. I can't seem to get the simulator to produce the interrupt flag.
In the past, I have used the AtMega328P in the simulator with equivalent code, and it works fine.
ISR(PORTA_PORT_vect)
{
//In this function we must:
//1. Shift all data up
shiftUp();
//2. Get new 8th bit
bit8 = VPORTA.IN & (1 << 1);
//3. Set Data Output Pin to bit0
if(bit0 == 0)
VPORTA.OUT &= ~(1 << 3);
else
VPORTA.OUT |= (1 << 3);
//4. Calculate new dimValue and dimMilliseconds
calcDim();
calcDelay();
}
int main(void)
{
initVariables();
/*
Below this, we must set the Data Direction (DD) of each pin we assigned.
*/
//Below, set the ISC of the Zero Cross Pin and the Clock Pin to allow interrupts
PORTA_PIN0CTRL |= 0b00000001; //Zero Cross
//PORTA_PIN1CTRL = 0b00000000; //Data In
//PORTA_PIN2CTRL = 0b00000000; //Data Next
//PORTA_PIN3CTRL = 0b00000000; //Triac Control
PORTB_PIN0CTRL |= 0b00000001; //Clock
//VPORTB.INTFLAGS |= 0b00000001;
//Set Port direction.
VPORTA.DIR = 0x30;
VPORTB.DIR = 0x00;
/*
Below this, we must enable interrupts.
*/
sei();
/* Replace with your application code */
while (1)
{
}
}
Why are you writing to VPORTA and VPORTB? The Tiny204 doesn´t have this registers.
You enable interrupts on both edges for Pin 0 of Port A (PIN0CTRL bit 0 is set = BOTHEDGES) and you don´t clear the interrupt flag in your ISR of Port A. Please take a look at the data sheet:
The interrupt request remains active until the interrupt flag is cleared. See the peripheral's INTFLAGSregister for details on how to clear interrupt flags.

How to setup an interrupt driven SPI with stm32F4

I'am using STM32F4 board with CMSIS library and I want setup an interrupt driven SPI, it means an interrupt is triggered each time a byte is sent by the SPI peripheral. The initiaisation function is as below:
void init_SPI1(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStruct;
SPI_InitTypeDef SPI_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5|GPIO_Pin_4;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// connect SPI1 pins to SPI alternate function
//GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
//Set chip select high
GPIOA->BSRRL |= GPIO_Pin_4; // set PE4 high
// enable peripheral clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
/* configure SPI1 in Mode 0
* CPOL = 0 --> clock is low when idle
* CPHA = 0 --> data is sampled at the first edge
*/
SPI_StructInit(&SPI_InitStruct); // set default settings
SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines
SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high
SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle
SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft ; // set the NSS management to internal and pull internal NSS high
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first
SPI_Init(SPI1, &SPI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable SPI1*/
SPI_Cmd(SPI1, ENABLE);
return;
}
Then i just loopback SPI_MOSI to SPI_MISO and use a function that transmit the data (a very basic function that takes data from a buffer and then uses CMSIS functions for the transmission). The problem is that when the SPI interrupt is triggered, the program won't get out from the handler. the handler function looks lihe this:
void SPI1_IRQHandler()
{
int a;
a++;
SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_TXE);
return;
}
Is it a problem in the CMSIS library, or I am not configuring the SPI interrupt in the good way? Please guide me to the right point.
EDIT
This is the function i use for data transmission
void write_SPI1()
{
int i;
for (i=0;i<SPI_TX_MAX; i++)
{
SPI_I2S_SendData(SPI1,spiTxBuff[i]);
SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);
}
}
and the interruption deals with the data reception, it just fill spiRxBuff when receiving new data.
void SPI1_IRQHandler()
{
while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)== RESET);
spiRxBuff[spiRxCount]= SPI_I2S_ReceiveData(SPI1);
spiRxCount++;
}
The variable used for Reception / Transmission are declared as below :
uint8_t spiTxBuff[SPI_TX_MAX] = {0x01,0x02,0x03,0x04,0x05,0x06};
uint8_t spiRxBuff[SPI_RX_MAX];
static volatile int spiRxCount= 0; // used in SPI1_IRQHandler
what is strange now is that i'am having {0x01,0x02,0x03,0x05,0x06} in spiRxBuff instead of {0x01,0x02,0x03,0x04,0x05,0x06}, but using debug mode the data in spiRxBuff are correct, what goes wrong in your opinion ?
You did not show the function doing the transmit, so I don't know exactly what are you trying to accomplish
Transmitting in a loop
If you are transmitting from a function (in a loop), then you don't need interrupts at all, just make sure that the TXE flag is set before you transmit. Note that you have to interleave sending and receiving somehow.
void SPI1_Transmit(uint8_t *send, uint8_t *receive, int count) {
while(count-- > 0) {
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)!=SET) {
if(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)==SET)
*receive++ = SPI_I2S_ReceiveData(SPI1);
}
SPI_I2S_SendData(SPI1, *send++);
}
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE)!=SET) {
/* wait for the last incoming byte */
}
*receive++ = SPI_I2S_ReceiveData(SPI1);
}
Transmitting from interrupt
The TXE interrupt flag is set as long as the SPI device is not busy sending. If you don't do something about it in the interrupt handler, it will trigger an interrupt immediately again and again. You can't clear it manually, but by transmitting another byte, and resetting the transmit interrupt enable flag before sending the last byte.
volatile int spi1_tx_count, spi1_rx_count;
uint8_t *spi1_tx_ptr;
volatile uint8_t *spi1_rx_ptr;
/* set these global variables before enabling interrupts */
void SPI1_IRQHandler() {
if (SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_TXE) == SET) {
if(--spi1_tx_count < 1)
SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_TXE, DISABLE);
SPI_I2S_SendData(SPI1, *spi1_tx_ptr++);
}
if(SPI_I2S_GetITStatus(SPI1, SPI_I2S_IT_RXNE) == SET) {
*spi_rx_ptr++ = SPI_I2S_ReceiveData(SPI1);
spi1_rx_count++;
}
}
Using DMA
The above examples are using processor power and cycles for a task that can be handled by the DMA conroller alone. A lot of (if not all) processor cycles, if you are talking to a peripheral at 2 MBit/s.
See Project/STM32F4xx_StdPeriph_Examples/SPI/SPI_TwoBoards in the library for an example.
Sorry, I haven't noticed at all that you've amended the question. Look like notifications are sent on new comments or answers, but not on edits.
There are multiple problems with your code. In write_SPI1(), I'd enable RX interrupt only once before the loop, there is no need to do it again and again. Also, you should definitely check whether the TX register is available before sending.
void write_SPI1() {
int i;
SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);
for (i=0;i<SPI_TX_MAX; i++) {
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE)!=SET)
;
SPI_I2S_SendData(SPI1,spiTxBuff[i]);
}
}
It is however a bad idea to wait on a flag in the interrupt handler. If RXNE is the only possible interrupt source, then you can proceed straight to receiving.

PIC12LF1822 UART Programming with External Fosc

I am currently working with PIC12LF1822 a Microchip series Controller. In that I need to configure EUSART in 8-bit Asynchronous mode and pulse generation of 1MHZ using PWM...
First I started with UART send and receive of data..But after setting including oscillator selection in config register, my code is not working and failed to send the character via tx pin(RA0)..
I analysed deeply,but I can't able to find a solution for this. Can anybody suggest to solve this issue.
Below I had pasted my code,
#include<htc.h>
#include <PIC12LF1822.H>
#include "BIPOLAR_SERIAL.C"
#define _XTAL_FREQ 12000000
//Configuration word 1 register for oscillator selection
__CONFIG(CP_OFF & BOREN_OFF & WDTE_OFF & IESO_OFF & FCMEN_OFF & PWRTE_ON & CPD_OFF & FOSC_XT);
//Configuration word 2 register for disabling Low-Voltage program
__CONFIG(LVP_OFF);
void PWM_Duty_Cyle(unsigned int duty_cyc)
{
CCPR1L = duty_cyc>>2;
CCP1CON &= 0xcf;
CCP1CON |= ((duty_cyc & 0x03)<<4);
}
void PWM_Init()
{
TRISA2 = 0; //PWM Pin as output
CCP1CON = 0x0c; //PWM mode: P1A, P1C active-high; P1B, P1D active-high
PR2 = 0x00; //Timer Period Configuration
T2CON = 0x00; //Timer2 Prescale as 1
PWM_Duty_Cyle(0); //Initialize PWM to 0 percent duty cycle
T2CON |= 0x04; //Enable Timer2
}
void main()
{
APFCON = 0;
ANSA0=0;ANSA1=0;ANSA2=0;
serial_init();
serial_tx('S');
// PWM_Init();
// serial_str("PIC12LF1822_TEST");
while(1)
{
serial_tx('A');
serial_tx(' ');
}
}
In the above code I can't able to get character's 'A' as well as 'S'.
Note: I am using 12MHZ as Fosc and I had set the baud rate according to that..(SPBRG=77 for baud =900,brgh=1)
What is your "SerialInit()" and "SerialTx('S')" functions doing?
Post the code of these functions, I'd like to see how you're setting up your serial port
Probably you havn't set all the required bits (RCSTA, TXSTA, SPBRG). To setup these bits properly, be sure to know the appropriate BaudRate you want to have, if you need high speed be sure to setup SPBRGH correctly.
My two functions to transmit via UART when properly initialized :
void vTx232 (UC ucSend)
{
STATUS.RP0 = PIR1; //Sure we're in PIR1
while (PIR1.TXIF == 0);//While last TX not done
TXREG = ucSend; //Input param into TXREG
}
void vTxString(UC *ucpString)
{
while (*ucpString!= 0x00) //While string not at its end
{
vTx232(*ucpString); //Send string character
ucpString++; //Increm string pointer
}
}
Datasheet : PIC12LF1822