Cannot get ADC value and put it into a array STM32F103C8T6 - arm

I try to put ADC value into a 1d array and transmit it to PC.
But it is not work. I using HAL_ADC_GetValue() to read data from chanel0 of ADC1.
Here is my code:
// maxziedata = 2048.
uint8_t DATA_ALL[MAXSIZEDATA];
void ReadAll(){
memset(DATA_ALL, 0, sizeof(DATA_ALL));
delay_us(timeDelay);
int count =-1;
//Read 32 Row
for(int row=0; row<32; row++){
SelectRow(row); //Read 32 Row
for(int col=0; col<32; col++){
SelectCol(col); //Read 32 Column
++count;
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,50);
HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC);
delay_us(10);
uint16_t data = HAL_ADC_GetValue(&hadc1); // Data is alway equal 0
// if data = n, PC will received data.
DATA_ALL[count*2] = data & 0xff;
DATA_ALL[count*2+1] = (data >> 8) & 0xff;
HAL_ADC_Stop(&hadc1);
}
HAL_GPIO_WritePin(GPIOB,EN_COL_1_Pin,GPIO_PIN_SET);
}
HAL_GPIO_WritePin(GPIOA,EN_ROW_1_Pin,GPIO_PIN_SET);
}
If I fake data uint16_t data = HAL_ADC_GetValue(&hadc1); change to uint16_t data = count, PC will receive data.
When I transmit only one value of array, PC will be received data.
void ReadOne(int row, int col){
memset(SEND_DATA, 0, sizeof(SEND_DATA));
HAL_ADC_Start(&hadc1);
SelectRow(row);
SelectCol(col);
HAL_ADC_Start(&hadc1);
delay_us(100);
HAL_ADC_PollForConversion(&hadc1,1);
uint16_t avg = 0;
for(int i=0; i<samplingTimes; i++){
avg += HAL_ADC_GetValue(&hadc1);
}
SEND_DATA[(row*32+col)*2] = avg/samplingTimes & 0xff;
SEND_DATA[((row*32+col)*2)+1] = (avg/samplingTimes >> 8) & 0xff;
HAL_ADC_Stop(&hadc1);
delay_us(100);
}
Here is my config ADC:
The main problem is HAL_ADC_GetValue() cannot put data into array after step of loop

Related

how Converting 2 arrays of bytes (uint8_t) into a word (uint16_t)?

I want to convert two times the Signal[8] values into a uint16_t word, so I can send it via the SPI port.(shift register)?
I tried the following, but it doesn't work:
the code was like that, my you can compile it.
void senddata(void){
uint8_t NZero = 0;
uint16_t timeout;
uint8_t value ;
volatile uint8_t Signal[8]={RGB_NC_0, RGB_1, RGB_2, RGB_3, RGB_4, RGB_5, RGB_6, RGB_NC_7}; // to be set by the state machine
volatile uint8_t SPIData[16]={0};
for(int i=0;i<8;i++){
nonZero|= Signal[i];
}
int i , j;
//Set LATCH low
GPIO_WriteBit(LED_LATCH_PORT, LED_LATCH, Bit_RESET);
//Set blank high
GPIO_WriteBit(LED_BLANK_PORT, LED_BLANK, Bit_SET);
//Enable SPI
SPI_Cmd(LED_SPI, ENABLE);
//iterate through the registers
for(i = 2 - 1; i >= 0; i--){
//iterate through the bits in each registers
for(j = 8 - 1; j >= 0; j--){
valr = Signal[i] & (1 << j);
SPI_I2S_SendData(LED_SPI, value);
while(SPI_I2S_GetFlagStatus(LED_SPI, SPI_I2S_FLAG_TXE) == 0 && timeout < 0xFFFF) //Odota että TXE=1
{ timeout++; }
if(timeout == 0xFFFF){break;}
}
}
SPI_Cmd(LED_SPI, DISABLE); /*!< SPI disable */
GPIO_WriteBit(LED_LATCH_PORT, LED_LATCH, Bit_SET);//Set LATCH high
if(NZero){
GPIO_WriteBit(LED_BLANK_PORT, LED_BLANK, Bit_RESET);//Set BLANK low
}
else{
GPIO_WriteBit(LED_BLANK_PORT, LED_BLANK, Bit_SET);//Set BLANK high
}
}
You can combine each subsequent two bytes into the SPI port register as follows:
for(size_t i = 0; i < sizeof(signal/sizeof(*signal); i += 2)
{
spiPortRegister = (uint16_t)signal[i + 0] << 0
| (uint16_t)signal[i + 1] << 8;
// send via SPI here!
}
// a *totally* generic implementation might add special handling for
// odd arrays, in your specific case you can omit...
Analogously you split back on receiver side:
for(size_t i = 0; i < sizeof(signal/sizeof(*signal); i += 2)
{
// receive via SPI here
signal[i + 0] = (uint8_t) spiPortRegister >> 0;
signal[i + 1] = (uint8_t) spiPortRegister >> 8;
}
Note: Additions or shifts by 0 are unnecessary and only added for code consistency; they will be optimised away by compiler anyway, but you can omit, if you prefer. Similarly the casts in second case, but these in addition silent the compiler from warning about precision loss.
Note, though, that even though promotion to int occurs in first case int might only be of size of 16 bits – and as you apparently operate on a MCU chances for rise – in which case the shift could provoke overflow, thus undefined behaviour, thus the cast should be applied in any case!
Endianness independent
uint16_t get16(volatile uint8_t *table)
{
return *table | ((uint16_t)*(table + 1) << 8);
}
or depending on endianess
uint16_t get16(volatile uint8_t *table)
{
uint16_t result;
memcpy(&result, table, sizeof(result));
return result;
}

Variable number of bytes to Uint32_t

I have made this function which unpacks received I2C messages and puts the individual values in a uint32_t array. It works when I use a fixed macro function for a fixed number of 2 bytes into a uint16_t , but I attempted to use a for loop to append any number of bytes to my values, since different i2c packets might have different value types. My problem lays in the way I do the bit operations, my bitwise knowledge seems too limited. What is wrong with option 2 here?
#define BytesToU16LE(B) ( \
(uint16_t)((B)[1]) << 8 \
| (uint16_t)((B)[0]) \
)
uint8_t ezi2cBuffer[100];
void unpack_i2c_packet(uint8_t nb_values_in_packet, uint8_t bytes_per_value, uint32_t * values, uint8_t buffer_head_size)
{
uint8_t current_value_bytes[bytes_per_value];
uint16_t payload_size = bytes_per_value * nb_values_in_packet;
uint8_t current_value_index = 0;
if(!nb_values_in_packet | !bytes_per_value)
return;
for(int i = 0; i < payload_size; i++)
{
current_value_bytes[(i % bytes_per_value) + buffer_head_size] = ezi2cBuffer[i + buffer_head_size]; // message head does not contain values, separate from payload
if((i % bytes_per_value) == (bytes_per_value - 1))
{
/* OPTION 1 WITH MACRO WORKS */
values[current_value_index] = BytesToU16LE(current_value_bytes);
/* OPTION 2 FOR LOOP PUTS RANDOM DATA IN MY VAR ARRAY! */
for(int bi = 0; bi < bytes_per_value; bi ++)
{
values[current_value_index] |= ((uint32_t)(current_value_bytes[bi]) << (bi * 8));
}
current_value_index++;
}
}
}
values[current_value_index] is not initialized in OPTION 2. You should initialize it to zero or the value after loop will depend on the value before the loop.
/* OPTION 2 FOR LOOP PUTS RANDOM DATA IN MY VAR ARRAY! */
values[current_value_index] = 0; /* add this */
for(int bi = 0; bi < bytes_per_value; bi ++)
{
values[current_value_index] |= ((uint32_t)(current_value_bytes[bi]) << (bi * 8));
}

MAX6675 with PIC18F45k22 Data transmission via UART Problem

I am using MPLAB XC8 to program pic18f45k22 to read data from 2 thermocouples. The code showed 2 problems, The first is that during simulation, the data from the sensor is shifted (sent to the second address)
for Example: if I have 2 addresses 0x0D and 0x0F, and 2 values 100 and 95, and 100 should got to 0x0D and 95 to 0x0F. However 100 goes to 0x0F and 95 to 0x0D.
**The second ** appears after uploading the code to the MCU, and it is that the MCU cannot Read any data from the sensors.
this is the main code:
void main(void) {
//SPI configuration
spiInit();
ANSELB = 0x00; //PORTB bits as digital
TRISB3 = 0; //GPIO as CS output
TRISB4 = 0;
TRISB5 = 0;
LATBbits.LATB3 = 1;
LATBbits.LATB4 = 1;
LATBbits.LATB5 = 1;
timer1init(); //initiate timer1
uartinit(9600); //initiate UART
__delay_ms(100);
while(1){
switch (cnt){ //timer interrupt routine every 1 second
//thermocouple code
case 50:
LATB3 = 0; //turn on CS
thercoup1 = spiRead(0)<<8; //Read first byte
thercoup1 |= spiRead(0); //add second byte with first one
LATB3 = 1; //turn off CS1
thercoup1 = (thercoup1>>4);
//thercoup1 = (thercoup1>>3)*0.25; //another method for calculating thermocouple value
LATB4 = 0; //turn on CS1
thercoup2 = spiRead(0)<<8; //Read first byte
thercoup2 |= spiRead(0); //add second byte with first one
LATB4 = 1; //turn off CS1
thercoup2 = (thercoup2>>4); //right shift of the reading
HMT_WriteVPN16(0x08000C, thercoup1); //send thermocouple1 data to 0x08000C
HMT_WriteVPN16(0x08000E, thercoup2); //send thermocouple2 data to 0x08000E
cnt = 0; //reset timer
break;
}
}
}
void __interrupt() ISR (void){
timer();
UART_Read();
}
And This is the configuration code of SPI module.
void spiInit(void)
{
ANSELC = 0x00;
SSP1STATbits.SMP = 0; //input Data is sampled at the middle
SSP1STATbits.CKE = 0; //Transmission occurs from Idle to Active
//Master mode Fosc/4
SSP1CON1bits.SSPM0 = 0;
SSP1CON1bits.SSPM1 = 0;
SSP1CON1bits.SSPM2 = 0;
SSP1CON1bits.SSPM3 = 0;
//
SSP1CON1bits.CKP = 1; //clock polarity is high
SSP1CON1bits.SSPEN = 1;//Serial communication is Enabled
SSP1CON1bits.SSPOV = 0;//Overflow is off
SSP1CON1bits.WCOL = 0;//Write collision is off
TRISCbits.RC5 = 1; //SDO is Disabled
TRISCbits.RC4 = 1; //SDI is Enabled
TRISCbits.RC3 = 0; //SCK is Enabled
}
unsigned short spiRead(unsigned char dat) //REad the received data
{
SSPBUF= dat; //the data loaded on the SSPBUF are not important.
while(!SSPSTATbits.BF); //save the received data from the slave.
return(SSPBUF);
}

Writing 9-bit values to byte array (or EEPROM) without wasting remaining bit in the following byte

I could not found an answer with google so i went for it and programmed quite a few hours.
I want to save 9-bit values to eeprom without wasting the other 7 bits.
I save values that would be up to 500 and i have not much EEPROM left.
The same principle can be applied to arrays, which i did just to not waer down the EEPROM.
So I made this little program:
/*
* Write only a certain number of bits to EEPROM.
*
* keeps the other bit in the byte of the eeprom as they are.
*
* Working version with 9 bits:
* 2019-10-03 15:57
* 2019-10-03 22:09 tested with chars too
* 2019-10-04 08:25 works with 7 bit chars also!
* 2019-10-04 12:27 fixed the combining of oldByte and new values in writeBitsToEEPROM(), because chars like 'ö' altered previous bit (left side) that should not have been altered.
*
*/
#include "arduino.h"
#include "EEPROM.h"
#include "math.h"
#define BIT_BLOCKS_COUNT 15
#define BLOCK_BYTE_COUNT 17
#define ARRAY_SIZE BLOCK_BYTE_COUNT+2
//TODO: change back to original value
#define EEPROM_SIZE ARRAY_SIZE
byte fakeEEPROM[ARRAY_SIZE] = {0};
String byteToString(byte value){
char byteChar[9];
byteChar[8] = '\0'; //we need a terminator
for(int i=7; i>=0; i--){
byteChar[7-i] = (value & (1 << i)) ? '1' : '0';
}
return String(byteChar);
}
String byteToString(unsigned long value, byte bytesToRead){
String str1 = byteToString(value >> 8);
String str2 = byteToString(value & 0xFF);
return str1 + " " + str2;
}
int globBlockStartAdress = 0;
byte globNumberOfBits = 0;
int globBlockSizeBytes = 0;
bool initBitBlock(int blockStartAdress, int blockCount, byte numberOfBits) {
globBlockStartAdress = blockStartAdress;
globNumberOfBits = numberOfBits;
// calc needed number of bytes and roud up
int tempBlockSize = blockCount * numberOfBits / 8;
if(blockCount * numberOfBits % 8)
tempBlockSize++;
// make number of bytes even
if(tempBlockSize % 2)
tempBlockSize++;
globBlockSizeBytes = tempBlockSize;
if(blockStartAdress + globBlockSizeBytes > EEPROM_SIZE)
return false;
return true;
}
/*
* Writes 1 to 9 bits to "internalAdress" within a designated block in eeprom
*/
void writeBitsToEEPROM(unsigned int bitsToBeWritten, int internalAdress){
//TODO: check if value is not higher than what can be stored
// if(bitsToBeWritten){
//
// }
int trueEEPROMAdress = globBlockStartAdress + internalAdress * globNumberOfBits / 8;
if(trueEEPROMAdress + 1 >= ARRAY_SIZE || internalAdress * globNumberOfBits / 8 >= globBlockSizeBytes){
Serial.print("globBlockSizeBytes: ");
Serial.println(globBlockSizeBytes);
Serial.println("FEHLER writeBitsToEEPROMWTF: ");
Serial.println(trueEEPROMAdress + 1);
Serial.println(internalAdress * globNumberOfBits / 8 );
}
byte startBitOfEEPROMByte = (internalAdress * globNumberOfBits) % 8;
unsigned int oldIntFromEEPROM = (fakeEEPROM[trueEEPROMAdress] << 8) | fakeEEPROM[trueEEPROMAdress + 1];
//Todo: change to eeprom
//filter out only the bits that need to be kept.
//EEPROM.get(trueEEPROMAdress, oldEEPROMByteBits);
// there might be bits in the byte that we dont want to change. left side and right side
unsigned int mask1KeepFromEEPROM = (0xFFFF << (16 - startBitOfEEPROMByte));
unsigned int mask2KeepFromEEPROM = (0xFFFF >> (startBitOfEEPROMByte + globNumberOfBits));
//if(16 - startBitOfEEPROMByte - numberOfBits > 0)
//mask2KeepFromEEPROM= (0xFFFF >> (startBitOfEEPROMByte + numberOfBits));
// masks combined
unsigned int maskIntToKeepFromEEPROM = mask1KeepFromEEPROM | mask2KeepFromEEPROM;
int newEEPROMInt = (oldIntFromEEPROM & maskIntToKeepFromEEPROM) | ((bitsToBeWritten << (16 - globNumberOfBits - startBitOfEEPROMByte) & ~maskIntToKeepFromEEPROM));
//Todo: change to eeprom
//write
//EEPROM.update(trueEEPROMAdress, newEEPROMByteBitsA);
fakeEEPROM[trueEEPROMAdress] = (newEEPROMInt >> 8);
fakeEEPROM[trueEEPROMAdress + 1] = (byte) newEEPROMInt;
if(trueEEPROMAdress + 1 > BLOCK_BYTE_COUNT){
Serial.println("FEHLER writeBitsToEEPROM");
Serial.println(trueEEPROMAdress + 1);
Serial.println("blockStartAdress");
Serial.println(globBlockStartAdress);
Serial.println("internalAdress");
Serial.println(internalAdress);
Serial.println("numberOfBits");
Serial.println(globNumberOfBits);
}
// Serial.print("trueEEPROMAdress: ");
// Serial.println(trueEEPROMAdress);
//
// Serial.print("internalAdress: ");
// Serial.println(internalAdress);
//
// Serial.print("globNumberOfBits: ");
// Serial.println(globNumberOfBits);
//
// Serial.print("bitsToBeWritten: ");
// Serial.println(byteToString(bitsToBeWritten,2));
//
// Serial.print(" mask1KeepFromEEPROM: ");
// Serial.println(byteToString(mask1KeepFromEEPROM,2));
//
// Serial.print("mask2KeepFromEEPROM: ");
// Serial.println(byteToString(mask2KeepFromEEPROM,2));
//
// Serial.print("maskIntToKeepFromEEPROM: ");
// Serial.println(byteToString(maskIntToKeepFromEEPROM,2));
//
// Serial.print("oldIntFromEEPROM: ");
// Serial.println(byteToString(oldIntFromEEPROM,2));
//
// Serial.print("newEEPROMInt: ");
// Serial.println(byteToString(newEEPROMInt,2));
//
// Serial.print("512: ");
// Serial.println(byteToString(512, 2));
//
// Serial.print("65535: ");
// Serial.println(byteToString(65535, 2));
}
unsigned int ReadBitsFromEEPROM(int internalAdress){
int trueEEPROMAdress = globBlockStartAdress + internalAdress * globNumberOfBits / 8;
byte startBitOfEEPROMByte = (internalAdress * globNumberOfBits) % 8;
if(trueEEPROMAdress + 1 > BLOCK_BYTE_COUNT)
Serial.println("FEHLER readBits");
unsigned int oldIntFromEEPROM = (fakeEEPROM[trueEEPROMAdress] << 8) | fakeEEPROM[trueEEPROMAdress + 1];
//Todo: change to eeprom
//filter out only the bits that need to be kept.
//EEPROM.get(trueEEPROMAdress, oldEEPROMByteBits);
unsigned int mask1KeepFromEEPROM = (0xFFFF << (16 - startBitOfEEPROMByte));
unsigned int mask2KeepFromEEPROM = (0xFFFF >> (startBitOfEEPROMByte + globNumberOfBits));
unsigned int maskIntToKeepFromEEPROM = mask1KeepFromEEPROM | mask2KeepFromEEPROM;
unsigned int valueFromEEPROM = ~maskIntToKeepFromEEPROM & oldIntFromEEPROM;
// Serial.print("trueEEPROMAdress: ");
// Serial.println(trueEEPROMAdress);
//
// Serial.print("internalAdress: ");
// Serial.println(internalAdress);
//
// Serial.print("numberOfBits: ");
// Serial.println(numberOfBits);
//
// Serial.print(" mask1KeepFromEEPROM: ");
// Serial.println(byteToString(mask1KeepFromEEPROM,2));
//
// Serial.print("mask2KeepFromEEPROM: ");
// Serial.println(byteToString(mask2KeepFromEEPROM,2));
////
// Serial.print("maskIntToKeepFromEEPROM: ");
// Serial.println(byteToString(maskIntToKeepFromEEPROM,2));
////
// Serial.print("oldIntFromEEPROM: ");
// Serial.println(byteToString(oldIntFromEEPROM,2));
return (valueFromEEPROM >> (16 - globNumberOfBits - startBitOfEEPROMByte));
}
void setup() {
Serial.begin(57600);
Serial.print(F("\n# Programversion: "));
Serial.print(__TIME__);
Serial.print(" ");
Serial.println(__DATE__);
Serial.println("Setup finished");
delay(1000);
}
void printEEPROM(){
for(int i = 0; i < ARRAY_SIZE; i++){
byte b;
//Todo: change to eeprom
//EEPROM.get(i, b);
b = fakeEEPROM[i];
Serial.print(byteToString(b));
Serial.print(" ");
}
Serial.println();
}
void testNumbers() {
Serial.println("bits?");
while( ! Serial.available());
String input = Serial.readString();
unsigned int value = input.toInt();
initBitBlock(1, 15, 9);
// Serial.print("value: ");
// Serial.println(byteToString(value));
for(int i = 0; i < BIT_BLOCKS_COUNT;i++){
for(int j = 0; j < BLOCK_BYTE_COUNT; j++){
fakeEEPROM[j] = 0xFF;
if(j > BLOCK_BYTE_COUNT)
Serial.println("FEHLER testNumbers");
}
// Serial.print("EEPROM before: ");
// printEEPROM();
writeBitsToEEPROM(value, i);
Serial.print("Returned: ");
Serial.println(ReadBitsFromEEPROM(i));
// Serial.print("EEPROM after: ");
// printEEPROM();
// Serial.println();
}
delay(1000);
}
#define CHAR_COUNT 16
void testChars() {
// Serial.println("bits?");
// while( ! Serial.available());
// String input = Serial.readString();
//
// unsigned int value = input.toInt();
initBitBlock(1, CHAR_COUNT, 7);
Serial.println("string?");
while( ! Serial.available());
String input = Serial.readString();
Serial.println(input);
char testString[CHAR_COUNT] = {'\0'};
input.toCharArray(testString, CHAR_COUNT, 0);
for(int j = 0; j < ARRAY_SIZE; j++){
fakeEEPROM[j] = 0;//xFF;
}
for(int i = 0; i < CHAR_COUNT; i++){
Serial.print("EEPROM before: ");
printEEPROM();
writeBitsToEEPROM(testString[i], i);
Serial.print("EEPROM after: ");
printEEPROM();
Serial.println();
}
Serial.println("Returned: ");
for(int i = 0; i < CHAR_COUNT; i++){
Serial.print((char) ReadBitsFromEEPROM(i));
}
Serial.println();
delay(1000);
}
void loop(){
testChars();
testNumbers();
}
which of course it not complete. Its just for saving those 9-bit values.
My question is: Has anyone else programmed a function like this - or knows where to find this - that is not limited to 9 bits (10 bits will span over 3 bytes)?
This function should take the number of bits given by bitsPerVal from each value in the input array pVals and pack them into the byte array pointed to by pOutBytes:
#include <stdint.h>
void pack_bits(uint32_t *pVals, size_t numVals, int bitsPerVal, uint8_t *pOutBytes)
{
uint32_t mask = ~(UINT32_MAX << bitsPerVal);
int outBitsLeft = 8;
int inBitsLeft = bitsPerVal;
while(numVals > 0)
{
if(inBitsLeft > outBitsLeft)
{
inBitsLeft -= outBitsLeft;
*pOutBytes |= (*pVals & mask) >> inBitsLeft;
mask >>= outBitsLeft;
outBitsLeft = 0;
}
else
{
outBitsLeft -= inBitsLeft;
*pOutBytes |= (*pVals & mask) << outBitsLeft;
mask = ~(UINT32_MAX << bitsPerVal);
inBitsLeft = bitsPerVal;
--numVals;
++pVals;
}
if(0 == outBitsLeft)
{
outBitsLeft = 8;
++pOutBytes;
}
}
}
The array pointed to by pOutBytes must suitably sized (ie ((numVals*bitsPerVal) + 7) / 8) and initialised to zero before calling. You can write it to your EEPROM after.
Hopefully this works well, I have done much testing on it though.
Here is an example of how 10 bits (actually 16-bits when written...) from 2 different fields could write to 16-bits of output.
struct EEPROM_Output
{
uint16_t a : 9; // 0 - 511 can be stored here
uint16_t b : 1; // 0 or 1 here.
uint16_t pad : 6; // Future use - we place this here to make it obvious that there are bits remaining.
};
void foo()
{
struct EEPROM_Output save;
save.a = 100;
save.b = 1;
WriteToEEPROM(&save, sizeof(save));
}

Is this code for initializing an SD card in SPI mode correct?

I want to initialize an SD card manually from an Arduino Mega 2560 and read its contents.
I've read a lot of manuals explaining how to properly do it, as well as the Arduino SD library code, but I can't get it to work.
uint8_t spi_byte(uint8_t byte) {
SPDR = byte;
asm volatile("nop");
while(!(SPSR & B10000000));
uint8_t response = SPDR;
return response;
}
uint8_t sd_cmd(uint8_t cmd, uint32_t args) {
if(cmd != 0x40) while(spi_byte(0xFF) != 0xFF);
spi_byte(cmd);
int8_t c;
for(c = 3; c >= 0; --c) spi_byte(args >> (c << 3));
uint8_t crc;
if(cmd == 0x40) crc = 0x95;
else if(cmd == 0x48) crc = 0x87;
else crc = 0xFF;
spi_byte(crc);
uint8_t response;
for(c = 16; ((response = spi_byte(0xFF)) & 0x80) && c; --c);
/*if((cmd < 0x51) || (cmd > 0x59))*/ spi_byte(0xFF); //S
return response;
}
void sd_init() {
DDRB &= B11110000;
PORTB |= B0001; //set CS pull-up resistor (just-in-case)
DDRB |= B0001; //set CS to output
PORTB |= B1000; //set MISO pull-up resistor (just-in-case)
SPCR = B01010010; //no interrupt, MSB first, master, mode 0, fosc/64 (250 kHz)
SPSR &= ~1; //clear SPI double speed
DDRB |= B0110; //set SCK and MOSI to output
delayMicroseconds(200000);
uint8_t c;
cli();
for(c = 0; c < 10; ++c) spi_byte(0xFF); //synchronize clock
clb(PORTB, 0); //set CS low
uint8_t response;
uint16_t timeout = 1024;
while((response=sd_cmd(0x40, 0)) != 0x1) { //CMD0: reset card
if((!response) || (response == 0xFF)) error(3); //we don't even have a card
if(!--timeout) error(7); //timed out
}
if(sd_cmd(0x48, 0x1AA) != 1) error(1); //CMD8: make sure we are using SD v2
for(c = 0; c < 4; ++c) spi_byte(0xFF);
do {
sd_cmd(0x77, 0); //CMD55: introduce application-specific command
response = sd_cmd(0x69, 0x40000000); //ACMD41: initialize card
if(!--timeout) error(8); //timed out
} while(response != 0);
sd_cmd(0x7A, 0); //CMD58: read OCR
response = spi_byte(0xFF);
if((response & B11000000) != B11000000) error(2); //make sure we are using SDHC
for(c = 0; c < 3; ++c) spi_byte(0xFF);
stb(PORTB, 0); //set CS high
SPCR = B01010000; //fosc/4 (4 MHz)
SPSR |= 1; //set SPI double speed (8 MHz)
for(c = 0; c < 10; ++c) spi_byte(0xFF); //synchronize clock
sei();
return;
}
void sd_read(uint8_t* buffer, uint32_t block, uint8_t start2, uint8_t size2) {
/*start2 and size2 are in 2 byte units, size2 = 0 means whole block (512 B)*/
cli();
block <<= 9; //S//D
clb(PORTB, 0); //set CS low
uint8_t response;
if((response=sd_cmd(0x51, block))) { //CMD17: read single block
Serial.begin(9600); //D
Serial.println(response, HEX); //D
error(10);
}
while(spi_byte(0xFF) != 0xFE) ; //TODO: timeout error 9
uint8_t b = 0; uint8_t end = 0;
do {
if((b >= start2) && (!end)) {
*(buffer++) = spi_byte(0xFF);
*(buffer++) = spi_byte(0xFF);
--size2;
if(!size2) end = 1;
}
else {
spi_byte(0xFF);
spi_byte(0xFF);
}
++b;
} while(b); //repeat 256 times
spi_byte(0xFF); spi_byte(0xFF); //two more bytes to close
stb(PORTB, 0); //set CS high
spi_byte(0xFF);
sei();
return;
}
Some days it works perfectly, other times it just locks up at initialization time, and finally right now I'm trying to read SD card contents and it just displays 0x55AA forever. I suspect that it is a hardware problem, but I'd like to rule out the possibility that my code might be wrong. Also, I don't know why I have to multiply reading address by 512. Being this an SDHC card, I would expect addresses to be in blocks, right?

Resources