SD over SPI returns invalid response on CMD8 - embedded

I'm working on an SPI SD driver for an LPC4088 microcontroller. However, when I send CMD8 (after CMD0) to detect if I'm working with a V2 or high capacity card, I get a weird response. Instead of getting a correct response( 0x01 for highest bits, 0x1AA for the lower 12) or an error I get 0x00 00 00 02 1F, which doesn't make any sense to me at all.
Code I use for initialization:
bool initialize () {
//0. Initialize SPI
SPI::init();
//1. Set clock to 400kHz
SPI::set_clock(400000);
//2. Assert CS signal (=0)
assert_cs();
// 3. Delay at least 74 clocks
delay8(10);
// 4. Deassert CS signal
deassert_cs();
// 5. Delay at least 16 clocks
delay8(2);
uint8_t argument[4];
reset_argument(argument);
// 6. Send CMD0 (reset, go to idle)
if (!send_command(CMD::GO_IDLE_STATE, CMD_RESPONSE_SIZE::GO_IDLE_STATE, response, argument)) {
return false;
}
// 7. Send CMD8
bool version2;
reset_argument(argument);
pack_argument(argument, 0x1AA);
if (!send_command(CMD::SEND_IF_COND, CMD_RESPONSE_SIZE::SEND_IF_COND, response, argument)) {
return false;
}
if ((response[0] & 0xFE) == 0x04) {
//unknown command. This means we have version1
version2 = false;
} else if (response[0] & 0xFE) {
//other error, let's bail
return false;
} else {
//Response, we're version2
version2 = true;
if (response[4] != 0xAA) {
return false;
}
}
//....
}
send_command code:
bool send_command(CMD::value cmd, uint8_t response_size, uint8_t *response, uint8_t *argument) {
assert_cs();
Crc7_SD crc;
crc += cmd | 0x40;
crc += argument[3] & 0xFF;
crc += argument[2] & 0xFF;
crc += argument[1] & 0xFF;
crc += argument[0] & 0xFF;
SPI::send(cmd | 0x40);
SPI::send(argument[3] & 0xFF);
SPI::send(argument[2] & 0xFF);
SPI::send(argument[1] & 0xFF);
SPI::send(argument[0] & 0xFF);
SPI::send((crc << 1) | 1);
volatile uint8_t data;
{
unsigned int timeout = SD_CMD_TIMEOUT;
do {
data = SPI::receive();
--timeout;
} while(timeout && (data & 0x80));
if (timeout == 0) {
deassert_cs();
return false;
}
}
for (int i = 0; i < response_size; i++) {
//First byte is already read above
if (response) {
response[i] = data;
}
data = SPI::receive();
}
deassert_cs();
return true;
}
To make sure that I didn't had an error in the SPI protocol I've verified the input and output with a logic analyzer. Result: CMD0 followed by CMD8. It seems that I'm sending the correct commands, but still I get this weird response.
Additional info about the setup:
Microcontroller is an LPC4088
Microcontroller is connected with this OEM board
The SD card module is connected to the serial expansion connector of the OEM board
The logic analyzer is connected to the SD card module
I've used 2 different versions of both the microcontroller and the OEM board to rule out that there is a hardware error in one of those. Unfortunately I don't have a second SD controller available.
I've used a SanDisk Ultra SDHC 4GB Class 6 SD card and a Transcend SDHC 4GB Class 4 SD card, both gave exactly the same result.
And last but not least, I have very little experience with embedded software, so it might just be some small stupid error.

It turned out that there was some noise on the MISO line. The code was correct, but due to the noise the microcontroller got a different result then intended. With the help of some electronics guy I was able to filter this by soldering a capacitor between MISO and ground.

Related

MSP430 I2C SCL line idling high (when it should be idling low)

I have the MSP430 configured as an i2c master device and it is talking with two slave devices: a battery fuel gauge (LTC2943) and a battery charger (LT8491 evaluation board). I noticed that when talking with the battery charger, a duplicate byte gets sent over the i2c bus (this is bad); let's call it a 'ghost' byte. I only see this ghost/duplicate byte when talking with the battery charger but never with the fuel gauge. Both of those slave devices are on the same bus and I'm performing the same operation on both of them (reading 2-bytes); see code below. After several days of frustration, I noticed a peculiar difference between the two devices…
I noticed that when I talk to the fuel gauge (i2c address 0x64), the i2c clock line (SCL) idles low. But when I talk to the battery charger (i2c address 0x10) the SCL line idles high. Notice the SCL line behavior after the address byte in the provided pictures (links below). Per the MSP430 datasheet, it is my understanding that the SCL line should be idling LOW after the slave the address is pushed on the line (see page 833 of the MSP430 family guide here: www.ti.com/.../slau367p.pdf). There's a comment that says: "Bus stalled (SCL held low) until data available".
A few questions related to this:
Why does the SCL line idle differently on those two devices (see picture links below) even though they are on the same i2c bus and we are performing the same 2-byte read operation and using the same i2c driver code?
The MSP430 family guide (page 833) has that comment that says: "Bus stalled (SCL held low) until data available". Whose responsibility it is to hold the SCL low in this case? Is it the master (MSP430) or the slave device?
In the same page of the family guide (page 833), there are cases where it appears that a certain action needs to be performed DURING the transmission of a data byte, is this a hard requirement? For example, let's consider the case where we want to write one byte to the slave device, then follow it with a repeated start and then read one byte. The timing diagram on page 833 implies that we need to set UCTR=0 and UCTXSTT=1 DURING the transmission of the current data byte. What would happen if we set these registers AFTER the data byte has been transmitted?
The 'ghost' byte that I am seeing when talking with the battery charger is basically the MSP430 pushing the contents of the TXBUF out on the bus again! This occurs even after we have already configured the the MSP430 to be in receive mode. Please notice how/when/where I am toggling P4.6 in code as well as in the logic captures (see pictures). Why does this ghost byte happen?! Why does the MSP430 push it's TXBUF out on the line again?
Zoomed out picture of i2c communication:
Zoomed in picture with fuel gauge (good communication):
Zoomed in picture with battery charger (bad communication):
My code:
#include <string.h>
#include "driverlib.h"
#define BATTERY_CHARGER_I2C_ADDR ( 0x10 )
#define FUEL_GAUGE_I2C_ADDR ( 0x64 )
#define GENERAL_I2C_TIMEOUT_MS ( 3 ) //When waiting for an i2c flag/condition, timeout after 3 milliseconds so we don't get stuck waiting forever
//local (static) functions
static void init_hardware( void );
static bool hwm_i2c_master_receive_data( uint8_t slave_addr, uint8_t* read_ptr, uint8_t size_bytes );
static bool hwm_i2c_master_send_data( uint8_t slave_addr, uint8_t* write_ptr, uint8_t size_bytes, bool issue_stop );
void main (void)
{
uint8_t write_data;
uint8_t read_data[2];
//Initialize HWM manager
init_hardware();
while(1)
{
__delay_cycles( 1000000 ); //delay for about 1 second (1 cycle ~ 1us)
//read 2 bytes from fuel gauge
write_data = 0x08;//address of voltage register
hwm_i2c_master_send_data( FUEL_GAUGE_I2C_ADDR, &write_data, 1, false );
hwm_i2c_master_receive_data(FUEL_GAUGE_I2C_ADDR, read_data, 2);
//read 2 bytes from battery charger
write_data = 0x28;//address of Rsense1 configuration register
hwm_i2c_master_send_data( BATTERY_CHARGER_I2C_ADDR, &write_data, 1, false );
hwm_i2c_master_receive_data( BATTERY_CHARGER_I2C_ADDR, read_data, 2);
}
} //main()
static void init_hardware( void )
{
Timer_A_initContinuousModeParam timerA_cont_param;
//Disable internal watchdog timer
WDTCTL = WDTPW | WDTHOLD;
//Set VLO to drive ACLK with a divider of 1 (i.e. run ACLK at 10KHz)
CS_initClockSignal( CS_ACLK, CS_VLOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
//This block of code basically initializes TimerA1 to run continuously at 1KHz
memset( &timerA_cont_param, 0, sizeof(timerA_cont_param) );
timerA_cont_param.clockSource = TIMER_A_CLOCKSOURCE_ACLK; //ACLK to drive TimerA1
timerA_cont_param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10; //Divide ACLK by 10 in order to get 1KHz
timerA_cont_param.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE; //Disable TimerA1 overflow interrupt
timerA_cont_param.timerClear = TIMER_A_DO_CLEAR; //Clear/reset TimerA1 counter
timerA_cont_param.startTimer = true; //Start TimerA1 counter
Timer_A_initContinuousMode( TIMER_A1_BASE, &timerA_cont_param );
//Configure P4.6 as an output pin for debugging (timing purposes)
GPIO_setAsOutputPin( GPIO_PORT_P4, GPIO_PIN6 );
GPIO_setOutputLowOnPin( GPIO_PORT_P4, GPIO_PIN6 );
//This block initializes the i2c peripheral
//Configure pins P1.6 (SDA) and P1.7 (SCL) for I2C (secondary module functionality)
GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_P1, ( GPIO_PIN6 | GPIO_PIN7 ), GPIO_SECONDARY_MODULE_FUNCTION );
PMM_unlockLPM5(); //Clear the LOCKLPM5 bit so the GPIO and i2c configuration takes effect
//Configure the I2C bus
EUSCI_B_I2C_initMasterParam i2c_master_init_param = {0};
i2c_master_init_param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK; //use SMCLK clock signal
i2c_master_init_param.i2cClk = CS_getSMCLK(); //Give SMCLK freq in Hz
i2c_master_init_param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS; //100KBps datarate
i2c_master_init_param.byteCounterThreshold = 0; //Don't care because 'no auto stop'
i2c_master_init_param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP; //We will handle the stop bit manually
EUSCI_B_I2C_initMaster( EUSCI_B0_BASE, &i2c_master_init_param );
EUSCI_B_I2C_enable(EUSCI_B0_BASE); //Enable the I2C bus (i.e. pull it out of reset state)
}
static bool hwm_i2c_master_receive_data( uint8_t slave_addr, uint8_t* read_ptr, uint8_t size_bytes )
{
bool proceed;
proceed = true;
//Basic sanity checks on address and size
if( NULL == read_ptr || 0 == size_bytes )
{
return false;
}
//Set P4.6 high for debugging (see scope captures)
GPIO_setOutputHighOnPin( GPIO_PORT_P4, GPIO_PIN6 );
UCB0I2CSA = slave_addr; //Set slave address
UCB0CTLW0 &= ~UCTR; //Set I2C bus in receiver (read) mode
UCB0IFG &= ~UCNACKIFG; //Clear NACK interrupt flag (fresh start)
UCB0CTLW0 |= UCTXSTT; //Issue START condition
//Wait for START condition to complete
TA1R = 0;
while( proceed && (UCB0CTLW0 & UCTXSTT) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (!(UCB0CTLW0 & UCTXSTT));
//If size is one byte, request STOP condition now! This is time critical (but not sure why :/)
if( proceed && (1 == size_bytes) )
{
UCB0CTLW0 |= UCTXSTP;
}
//Check that we received ACK from slave
proceed = proceed && (!(UCB0IFG & UCNACKIFG));
//Loop through and pull the requested number for bytes from the RX buffer
while( proceed && (size_bytes > 0) )
{
//Wait for RX buffer to be ready/full
TA1R = 0;
while( (!(UCB0IFG & UCRXIFG0)) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (UCB0IFG & UCRXIFG0);
if( proceed )
{
*read_ptr = UCB0RXBUF; //Pull byte out of RX buffer
read_ptr++; //Increment pointer
size_bytes--; //Decrement number of bytes left to read
//If there's only one byte left to read, request STOP condition. This is time critical (again, not sure why)
if( 1 == size_bytes )
{
UCB0CTLW0 |= UCTXSTP;
}
}
}
//Wait for the STOP condition to complete
TA1R = 0;
while( (UCB0CTLW0 & UCTXSTP) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (!(UCB0CTLW0 & UCTXSTP));
if( !proceed )
{
//If we got here, it means something went bad (e.g. timed out or slave NACK'ed),
//let's request STOP to terminate communication
UCB0CTLW0 |= UCTXSTP;
//wait for stop to complete
TA1R = 0;
while( (UCB0CTLW0 & UCTXSTP) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
}
//Clear P4.6
GPIO_setOutputLowOnPin( GPIO_PORT_P4, GPIO_PIN6 );
return proceed;
} //hwm_i2c_master_receive_data()
static bool hwm_i2c_master_send_data( uint8_t slave_addr, uint8_t* write_ptr, uint8_t size_bytes, bool issue_stop )
{
bool proceed;
proceed = true;
//Basic sanity checks on address and size
if( NULL == write_ptr || 0 == size_bytes )
{
return false;
}
UCB0I2CSA = slave_addr; //Set slave address
UCB0CTLW0 |= UCTR; //Set I2C bus in transmit mode
UCB0IFG &= ~UCNACKIFG; //Clear NACK interrupt flag (fresh start)
UCB0CTLW0 |= UCTXSTT; //Issue START condition
//Wait for START condition to complete
TA1R = 0;
while( proceed && (UCB0CTLW0 & UCTXSTT) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (!(UCB0CTLW0 & UCTXSTT));
//At this point, we have just pushed the slave address over the i2c line.
//According to the MSP430 datasheet, the MSP430 would/should hold the
//SCL line low until we put something in the UCB0TXBUF.
//In other words, during this delay, the SCL should be held low. This is
//true when talking with the fuel gauge (LTC2943) but is NOT the case when
//talking with the battery charger! Why is that?!
__delay_cycles( 100 ); //delay of ~100us, please notice the SCL line (pictures) during this delay
//Wait for tx buffer to be ready/empty
TA1R = 0;
while( proceed && (!(UCB0IFG & UCTXIFG0)) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (UCB0IFG & UCTXIFG0);
//Check that we received ACK from slave
proceed = proceed && (!(UCB0IFG & UCNACKIFG));
//Loop through and send the data
while( proceed && (size_bytes > 0) )
{
//Set P4.6 high for debugging
GPIO_setOutputHighOnPin( GPIO_PORT_P4, GPIO_PIN6 );
//Place byte in tx buffer for transmission
UCB0TXBUF = *write_ptr;
//Wait for byte to flush out of tx buffer
TA1R = 0;
while( proceed && (!(UCB0IFG & UCTXIFG0)) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (UCB0IFG & UCTXIFG0);
//Check the ACK after every byte to make sure it went ok
proceed = proceed && (!(UCB0IFG & UCNACKIFG));
//Increment write pointer and decrement remaining size
write_ptr++;
size_bytes--;
}
//If caller requested a STOP condition to be sent
if( proceed && issue_stop )
{
//Issue STOP condition
UCB0CTLW0 |= UCTXSTP;
//Wait for STOP condition to go through
TA1R = 0;
while( (UCB0CTLW0 & UCTXSTP) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
proceed = proceed && (!(UCB0CTLW0 & UCTXSTP));
}
if( !proceed )
{
//If we got here, it means something went bad (e.g. timed out or slave NACK'ed),
//let's request STOP to terminate communication
UCB0CTLW0 |= UCTXSTP;
//wait for stop to complete
TA1R = 0;
while( (UCB0CTLW0 & UCTXSTP) && (TA1R < GENERAL_I2C_TIMEOUT_MS) );
}
GPIO_setOutputLowOnPin( GPIO_PORT_P4, GPIO_PIN6 );
return proceed;
} //hwm_i2c_master_send_data()

STM32F769NI USB CDC host problem sending simple data to the device

I am making HID for some data acquisition system. There are a lot of sensors who store test data and when I need I get to them and connect via USB and take it. USB host sent 3 bytes and USB device, if bytes are correct, sends its stored data. Sounds simple.
Previously it was implemented on PC, but now I try to implement it on STM32F769 Discovery and have some serious problems.
I am using ARM Keil 5.27, code generated with STM32CubeMX 5.3.0. I tried just to make a plain simple program, later to integrate with the entire touchscreen interface. I tried to implement this code in main:
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
{
Transmission_function();
}
And the function itself:
#define DLE 0x10
#define STX 0x2
uint8_t tx_buf[]={DLE, STX, 120}, RX_FLAG;
uint32_t size_tx=sizeof(tx_buf);
void Transmission_function (void)
{
if (Appli_state == APPLICATION_READY)
{
i=0;
USBH_CDC_Transmit(&hUsbHostHS, tx_buf, size_tx);
HAL_Delay(50);
RX_FLAG=0;
}
}
It should send the message after I press the blue button on the Discovery board. All that I get is Hard Fault. While trying to debug, I tried manually to check after which action I get this error and it was functioning in stm32f7xx_ll_usb.c:
HAL_StatusTypeDef USB_WritePacket(USB_OTG_GlobalTypeDef *USBx, uint8_t *src,
uint8_t ch_ep_num, uint16_t len, uint8_t dma)
{
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t *pSrc = (uint32_t *)src;
uint32_t count32b, i;
if (dma == 0U)
{
count32b = ((uint32_t)len + 3U) / 4U;
for (i = 0U; i < count32b; i++)
{
USBx_DFIFO((uint32_t)ch_ep_num) = *((__packed uint32_t *)pSrc);
pSrc++;
}
}
return HAL_OK;
}
But trying to scroll back in disassembly I notice, that just before Hard Fault program was in this function inside stm32f7xx_hal_hcd.c, in case GRXSTS_PKTSTS_IN:
static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd)
{
USB_OTG_GlobalTypeDef *USBx = hhcd->Instance;
uint32_t USBx_BASE = (uint32_t)USBx;
uint32_t pktsts;
uint32_t pktcnt;
uint32_t temp;
uint32_t tmpreg;
uint32_t ch_num;
temp = hhcd->Instance->GRXSTSP;
ch_num = temp & USB_OTG_GRXSTSP_EPNUM;
pktsts = (temp & USB_OTG_GRXSTSP_PKTSTS) >> 17;
pktcnt = (temp & USB_OTG_GRXSTSP_BCNT) >> 4;
switch (pktsts)
{
case GRXSTS_PKTSTS_IN:
/* Read the data into the host buffer. */
if ((pktcnt > 0U) && (hhcd->hc[ch_num].xfer_buff != (void *)0))
{
(void)USB_ReadPacket(hhcd->Instance, hhcd->hc[ch_num].xfer_buff, (uint16_t)pktcnt);
/*manage multiple Xfer */
hhcd->hc[ch_num].xfer_buff += pktcnt;
hhcd->hc[ch_num].xfer_count += pktcnt;
if ((USBx_HC(ch_num)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) > 0U)
{
/* re-activate the channel when more packets are expected */
tmpreg = USBx_HC(ch_num)->HCCHAR;
tmpreg &= ~USB_OTG_HCCHAR_CHDIS;
tmpreg |= USB_OTG_HCCHAR_CHENA;
USBx_HC(ch_num)->HCCHAR = tmpreg;
hhcd->hc[ch_num].toggle_in ^= 1U;
}
}
break;
case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
break;
case GRXSTS_PKTSTS_IN_XFER_COMP:
case GRXSTS_PKTSTS_CH_HALTED:
default:
break;
}
}
Last few lines from Dissasembly shows this:
0x080018B4 E8BD81F0 POP {r4-r8,pc}
0x080018B8 0000 DCW 0x0000
0x080018BA 1FF8 DCW 0x1FF8
Why it fails? How could I fix it? I do not have much experience with USB protocol.
I will post my walkaround this, but I am not sure why it worked. Solution was to use EXTI0 interrupt instead of just detection if PA0 is high, as I showed I used here:
if (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
while (HAL_GPIO_ReadPin(BUTTON_GPIO_Port, BUTTON_Pin))
Transmission_function();
I changed it to this:
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
if(Appli_state == APPLICATION_READY){
USBH_CDC_Transmit(&hUsbHostHS, Buffer, 3);
}
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */
/* USER CODE END EXTI0_IRQn 1 */
}

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

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);
}

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

Embedded: SDHC SPI write issue

I am currently working at a logger that uses a MSP430F2618 MCU and SanDisk 4GB SDHC Card.
Card initialization works as expected, I also can read MBR and FAT table.
The problem is that I can't write any data on it. I have checked if it is write protected by notch, but it's not. Windows 7 OS has no problem reading/writing to it.
Though, I have used a tool called "HxD" and I've tried to alter some sectors (under Windows). When I try to save the content to SD card, the tool pop up a windows telling me "Access denied!".
Then I came back to my code for writing to SD card:
uint8_t SdWriteBlock(uchar_t *blockData, const uint32_t address)
{
uint8_t result = OP_ERROR;
uint16_t count;
uchar_t dataResp;
uint8_t idx;
for (idx = RWTIMEOUT; idx > 0; idx--)
{
CS_LOW();
SdCommand(CMD24, address, 0xFF);
dataResp = SdResponse();
if (dataResp == 0x00)
{
break;
}
else
{
CS_HIGH();
SdWrite(0xFF);
}
}
if (0x00 == dataResp)
{
//send command success, now send data starting with DATA TOKEN = 0xFE
SdWrite(0xFE);
//send 512 bytes of data
for (count = 0; count < 512; count++)
{
SdWrite(*blockData++);
}
//now send tow CRC bytes ,through it is not used in the spi mode
//but it is still needed in transfer format
SdWrite(0xFF);
SdWrite(0xFF);
//now read in the DATA RESPONSE TOKEN
do
{
SdWrite(0xFF);
dataResp = SdRead();
}
while (dataResp == 0x00);
//following the DATA RESPONSE TOKEN are a number of BUSY bytes
//a zero byte indicates the SD/MMC is busy programing,
//a non_zero byte indicates SD/MMC is not busy
dataResp = dataResp & 0x0F;
if (0x05 == dataResp)
{
idx = RWTIMEOUT;
do
{
SdWrite(0xFF);
dataResp = SdRead();
if (0x0 == dataResp)
{
result = OP_OK;
break;
}
idx--;
}
while (idx != 0);
CS_HIGH();
SdWrite(0xFF);
}
else
{
CS_HIGH();
SdWrite(0xFF);
}
}
return result;
}
The problem seems to be when I am waiting for card status:
do
{
SdWrite(0xFF);
dataResp = SdRead();
}
while (dataResp == 0x00);
Here I am waiting for a response of type "X5"(hex value) where X is undefined.
But most of the cases the response is 0x00 (hex value) and I don't get out of the loop. Few cases are when the response is 0xFF (hex value).
I can't figure out what is the problem.
Can anyone help me? Thanks!
4GB SDHC
We need to see much more of your code. Many µC SPI codebases only support SD cards <= 2 GB, so using a smaller card might work.
You might check it yourself: SDHC needs a CMD 8 and an ACMD 41 after the CMD 0 (GO_IDLE_STATE) command, otherwise you cannot read or write data to it.
Thank you for your answers, but I solved my problem. It was a problem of timing. I had to put a delay at specific points.