ESP32 - SPI "spi_bus_initialize: host already in use" with SDCARD - c++

I am trying to write to a sd card using an esp32. The problem is that I cannot mount the unit. The SPI bus does not seem to work. I am using VSPI, since using HSPI it restarts constantly, it seems to be due to the use of pin 12
My code is:
esp_err_t ret;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = format,
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
ESP_LOGI(TAG, "Using SPI peripheral");
//spi_host_device_t host = SDSPI_HOST_DEFAULT(); //Usa HSPI (SPI2) o VSPI (SPI3) host.
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.slot = VSPI_HOST;
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
//ret = spi_bus_initialize((spi_host_device_t)host.slot, &bus_cfg, 0);
ret = spi_bus_initialize(VSPI_HOST, &bus_cfg, 2);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
card = NULL;
return;
}
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT(); // SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = (gpio_num_t)cs_pin;
//slot_config.host_id = host.slot;
//ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount card.");
card = NULL;
return;
}
Also use esp_vfs_fat_sdmmc_mount instead of esp_vfs_fat_sdspi_mount because the esp_vfs_fat_sdspi_mount function does not exist. why?
Pin used:
CS: 5
SCLK: 18
MISO: 19
MOSI: 23
Use platformio with Visual Studio Code.
This is my output console:
(320) sdcard: Initializing SD card␛[0m
␛[0;32mI (321) sdcard: Using SPI peripheral␛[0m
␛[0;31mE (321) spi: SPI3 already claimed by spi master.␛[0m
␛[0;31mE (323) spi_master: spi_bus_initialize(232): host already in use␛[0m
␛[0;31mE (330) sdcard: Failed to mount card.␛[0m

Related

Xcode app for macOS. This is how I setup to get audio from usb mic input. Worked a year ago, now doesn't. Why

Here is my audio init code. My app responds when queue buffers are ready, but all data in buffer is zero. Checking sound in system preferences shows that USB Audio CODEC in sound input dialog is active. AudioInit() is called right after app launches.
{
#pragma mark user data struct
typedef struct MyRecorder
{
AudioFileID recordFile;
SInt64 recordPacket;
Float32 *pSampledData;
MorseDecode *pMorseDecoder;
} MyRecorder;
#pragma mark utility functions
void CheckError(OSStatus error, const char *operation)
{
if(error == noErr) return;
char errorString[20];
// see if it appears to be a 4 char code
*(UInt32*)(errorString + 1) = CFSwapInt32HostToBig(error);
if (isprint(errorString[1]) && isprint(errorString[2]) &&
isprint(errorString[3]) && isprint(errorString[4]))
{
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
}
else
{
sprintf(errorString, "%d", (int)error);
}
fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
}
OSStatus MyGetDefaultInputDeviceSampleRate(Float64 *outSampleRate)
{
OSStatus error;
AudioDeviceID deviceID = 0;
AudioObjectPropertyAddress propertyAddress;
UInt32 propertySize;
propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(AudioDeviceID);
error = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&propertyAddress,
0,
NULL,
&propertySize,
&deviceID);
if(error)
return error;
propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(Float64);
error = AudioObjectGetPropertyData(deviceID,
&propertyAddress,
0,
NULL,
&propertySize,
outSampleRate);
return error;
}
static int MyComputeRecordBufferSize(const AudioStreamBasicDescription *format,
AudioQueueRef queue,
float seconds)
{
int packets, frames, bytes;
frames = (int)ceil(seconds * format->mSampleRate);
if(format->mBytesPerFrame > 0)
{
bytes = frames * format->mBytesPerFrame;
}
else
{
UInt32 maxPacketSize;
if(format->mBytesPerPacket > 0)
{
// constant packet size
maxPacketSize = format->mBytesPerPacket;
}
else
{
// get the largest single packet size possible
UInt32 propertySize = sizeof(maxPacketSize);
CheckError(AudioQueueGetProperty(queue,
kAudioConverterPropertyMaximumOutputPacketSize,
&maxPacketSize,
&propertySize),
"Couldn't get queues max output packet size");
}
if(format->mFramesPerPacket > 0)
packets = frames / format->mFramesPerPacket;
else
// worst case scenario: 1 frame in a packet
packets = frames;
// sanity check
if(packets == 0)
packets = 1;
bytes = packets * maxPacketSize;
}
return bytes;
}
extern void bridgeToMainThread(MorseDecode *pDecode);
static int callBacks = 0;
// ---------------------------------------------
static void MyAQInputCallback(void *inUserData,
AudioQueueRef inQueue,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc)
{
MyRecorder *recorder = (MyRecorder*)inUserData;
Float32 *pAudioData = (Float32*)(inBuffer->mAudioData);
recorder->pMorseDecoder->pBuffer = pAudioData;
recorder->pMorseDecoder->bufferSize = inNumPackets;
bridgeToMainThread(recorder->pMorseDecoder);
CheckError(AudioQueueEnqueueBuffer(inQueue,
inBuffer,
0,
NULL),
"AudioQueueEnqueueBuffer failed");
printf("packets = %ld, bytes = %ld\n",(long)inNumPackets,(long)inBuffer->mAudioDataByteSize);
callBacks++;
//printf("\ncallBacks = %d\n",callBacks);
//if(callBacks == 0)
//audioStop();
}
static AudioQueueRef queue = {0};
static MyRecorder recorder = {0};
static AudioStreamBasicDescription recordFormat;
void audioInit()
{
// set up format
memset(&recordFormat,0,sizeof(recordFormat));
recordFormat.mFormatID = kAudioFormatLinearPCM;
recordFormat.mChannelsPerFrame = 2;
recordFormat.mBitsPerChannel = 32;
recordFormat.mBytesPerPacket = recordFormat.mBytesPerFrame = recordFormat.mChannelsPerFrame * sizeof(Float32);
recordFormat.mFramesPerPacket = 1;
//recordFormat.mFormatFlags = kAudioFormatFlagsCanonical;
recordFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
MyGetDefaultInputDeviceSampleRate(&recordFormat.mSampleRate);
UInt32 propSize = sizeof(recordFormat);
CheckError(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&propSize,
&recordFormat),
"AudioFormatProperty failed");
recorder.pMorseDecoder = MorseDecode::pInstance();
recorder.pMorseDecoder->m_sampleRate = recordFormat.mSampleRate;
// recorder.pMorseDecoder->setCircularBuffer();
//set up queue
CheckError(AudioQueueNewInput(&recordFormat,
MyAQInputCallback,
&recorder,
NULL,
kCFRunLoopCommonModes,
0,
&queue),
"AudioQueueNewInput failed");
UInt32 size = sizeof(recordFormat);
CheckError(AudioQueueGetProperty(queue,
kAudioConverterCurrentOutputStreamDescription,
&recordFormat,
&size), "Couldn't get queue's format");
// set up buffers and enqueue
const int kNumberRecordBuffers = 3;
int bufferByteSize = MyComputeRecordBufferSize(&recordFormat, queue, AUDIO_BUFFER_DURATION);
for(int bufferIndex = 0; bufferIndex < kNumberRecordBuffers; bufferIndex++)
{
AudioQueueBufferRef buffer;
CheckError(AudioQueueAllocateBuffer(queue,
bufferByteSize,
&buffer),
"AudioQueueAllocateBuffer failed");
CheckError(AudioQueueEnqueueBuffer(queue,
buffer,
0,
NULL),
"AudioQueueEnqueueBuffer failed");
}
}
void audioRun()
{
CheckError(AudioQueueStart(queue, NULL), "AudioQueueStart failed");
}
void audioStop()
{
CheckError(AudioQueuePause(queue), "AudioQueuePause failed");
}
}
This sounds like the new macOS 'microphone privacy' setting, which, if set to 'no access' for your app, will cause precisely this behaviour. So:
Open the System Preferences pane.
Click on 'Security and Privacy'.
Select the Privacy tab.
Click on 'Microphone' in the left-hand pane.
Locate your app in the right-hand pane and tick the checkbox next to it.
Then restart your app and test it.
Tedious, no?
Edit: As stated in the comments, you can't directly request microphone access, but you can detect whether it has been granted to your app or not by calling [AVCaptureDevice authorizationStatusForMediaType: AVMediaTypeAudio].

How do I transfer an image taken by ESP32-Cam over sockets?

I have an ESP32-Cam and I would like to save an image that was taken by it to my desktop. The ultimate goal would be to display the image in an Android app, but thats a different story.
In order to do this I thought I have to transfer the image with sockets.
The code beneath shows my example code. I have a very simple python program that connects to the WifiServer and prints whatever client.write() is writing.
However I am not sure how I am supposed to transfer the image in this way. Is this even possible? Because I have to transfer the images buffer (in this case fb->buf) right?
But how would I make an image out of that once I received the buffer e.g. in my python code?
It would be great, if someone could help me to get this running, since I never worked with this (images / sockets) before.
ESP Code
#include "esp_camera.h"
#include "Arduino.h"
#include "WiFi.h"
// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
// Variables
camera_fb_t * fb = NULL;
WiFiServer wifiServer(5005);
const char* ssid = "ssid";
const char* password = "password";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi.");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("\nConnected!");
Serial.println(WiFi.localIP());
wifiServer.begin();
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if (psramFound()) {
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Init Camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
}
void loop() {
WiFiClient client = wifiServer.available();
if (client) {
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
} else {
Serial.println("Camera capture succesfull!");
}
while (client.connected()) {
// How do I transfer the image? What do I have to do?
client.write(fb->buf);
}
client.stop();
Serial.println("Client disconnected");
}
}
Python code
import socket
sock = socket.socket()
host = "192.168.178.103" # esp ip
port = 5005 # esp port
sock.connect((host, port))
data = sock.recv(256)
print(data)
sock.close()
Here is Arduino code that worked for me (starting at the loop function)
//=======================================================================
// Main Program Loop
//=======================================================================
void loop() {
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("Connection to host failed");
delay(1000);
return;
}
Serial.println("Connected to server successful!");
// capture camera frame
camera_fb_t *fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return;
} else {
Serial.println("Camera capture successful!");
}
const char *data = (const char *)fb->buf;
// Image metadata. Yes it should be cleaned up to use printf if the function is available
Serial.print("Size of image:");
Serial.println(fb->len);
Serial.print("Shape->width:");
Serial.print(fb->width);
Serial.print("height:");
Serial.println(fb->height);
client.print("Shape->width:");
client.print(fb->width);
client.print("height:");
client.println(fb->height);
// Give the server a chance to receive the information before sending an acknowledgement.
delay(1000);
getResponse(client);
Serial.print(data);
client.write(data, fb->len);
esp_camera_fb_return(fb);
Serial.println("Disconnecting...");
client.stop();
delay(2000);
}
void getResponse(WiFiClient client) {
byte buffer[8] = { NULL };
while (client.available() > 0 || buffer[0] == NULL) {
int len = client.available();
Serial.println("Len" + len);
if (len > 8) len = 8;
client.read(buffer, len);
if (printReceivedData) {
Serial.write(buffer, len); // show in the serial monitor (slows some boards)
Serial.println("");
}
}
}
The python code to receive the image
import io
import socket
import time
import numpy as np
from PIL import Image
import connection_and_network_constants
serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# address '0.0.0.0' or '' work to allow connections from other machines. 'localhost' disallows external connections.
# see https://www.raspberrypi.org/forums/viewtopic.php?t=62108
serv.bind(('0.0.0.0', connection_and_network_constants.SOCKET_PORT))
serv.listen(5)
print("Ready to accept 5 connections")
def create_image_from_bytes(image_bytes) -> Image.Image:
stream = io.BytesIO(image_bytes)
return Image.open(stream)
while True:
conn, addr = serv.accept()
array_from_client = bytearray()
shape = None
chunks_received = 0
start = time.time()
shape_string = ''
while True:
# print('waiting for data')
# Try 4096 if unsure what buffer size to use. Large transfer chunk sizes (which require large buffers) can cause corrupted results
data = conn.recv(connection_and_network_constants.BUFFER_SIZE)
if not data or data == b'tx_complete':
break
elif shape is None:
shape_string += data.decode("utf-8")
# Find the end of the line. An index other than -1 will be returned if the end has been found because
# it has been received
if shape_string.find('\r\n') != -1:
width_index = shape_string.find('width:')
height_index = shape_string.find('height:')
width = int(shape_string[width_index + len('width:'): height_index])
height = int(shape_string[height_index + len('height:'): ])
shape = (width, height)
print("shape is {}".format(shape))
else:
chunks_received += 1
# print(chunks_received)
array_from_client.extend(data)
# print(array_from_client)
conn.sendall(b'ack')
# print("sent acknowledgement")
# TODO: need to check if sending acknowledgement of the number of chunks and the total length of the array is a good idea
print("chunks_received {}. Number of bytes {}".format(chunks_received, len(array_from_client)))
img: Image.Image = create_image_from_bytes(array_from_client)
img.show()
array_start_time = time.time()
image_array = np.asarray(img)
print('array conversion took {} s'.format(time.time() - array_start_time))
conn.close()
print('client disconnected')

Why receiving shifted and duplicated data in SPI communication between Raspberry Pi (master) and Nucleo l432kc boards (slaves)

​I've asked the same question on the ST Q&A forum and on the Raspberry Pi forum, but I didn't receive any answer. I hope that here there is someone that can help me.
I want to make communicate two Nucleo l432kc (slaves) with a Raspberry Pi (master) through the SPI protocol. On the Raspberry I'm using the Spidev API, while on the Nucleo I'm using the HAL SPI interface with DMA.
The only configuration that permits a stable transmission is the SPI_MODE_2 of Spidev that corresponds to the SPI_POLARITY_HIGH and SPI_PHASE_2EDGE configuration of the HAL.
With the above configuration I have two problems:
The messages sent by the master to the slaves arrive always correctly, but all the messages sent by the slaves to the master always arrive shifted by 1 bit on the right (e.g. if I send two bytes 0b00000011 0b00000001 I receive 0b00000001 0b10000000). It seems that the sampling of the MISO signal is delayed but I can't figure out why.
I receive the data on both the slaves regardless if the chip select is set or not. In the response of the slaves I have no collisions so I think that only the MISO bus is effectively set in high impedance mode in the slave when the NSS is high.
To test purpose I've tried to use the SPISlave class of the mbed framework,
this class cannot use the DMA so I can't use it in the real program. Using it I solve the first problem but the second persists.
Another thing that could be useful is that with the SPISlave class I can use all the 4 mode of the SPI protocol, of course the slaves and the master must use the same mode but is not import which one.
As I said before with the HAL interface I can use only the SPI_MODE_2.
This is the configuration code that runs on both the slaves:
// SPI
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 parameter configuration*/
hspi.Instance = SPI1;
hspi.Init.Mode = SPI_MODE_SLAVE;
hspi.Init.Direction = SPI_DIRECTION_2LINES; // full duplex mode
hspi.Init.DataSize = SPI_DATASIZE_8BIT; // dimension of 1 byte
hspi.Init.CLKPolarity = SPI_POLARITY_HIGH; // start and idle clk value
hspi.Init.CLKPhase = SPI_PHASE_2EDGE; // edge of sampling of data both on miso and mosi
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB; // bit order
hspi.Init.TIMode = SPI_TIMODE_DISABLE; // disabling the TI mode
hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // disable crc calc
hspi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; // disable NSS puls value
if (HAL_SPI_Init(&hspi) != HAL_OK)
return false;
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
// GPIO
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA1 ------> SPI1_SCK
PA11 ------> SPI1_MISO
PA12 ------> SPI1_MOSI
PB0 ------> SPI1_NSS
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// DMA
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi_rx.Instance = DMA1_Channel2;
hdma_spi_rx.Init.Request = DMA_REQUEST_1;
hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_rx.Init.Mode = DMA_NORMAL;
hdma_spi_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi_rx) != HAL_OK) return false;
__HAL_LINKDMA(&hspi,hdmarx,hdma_spi_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi_tx.Instance = DMA1_Channel3;
hdma_spi_tx.Init.Request = DMA_REQUEST_1;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_tx.Init.Mode = DMA_NORMAL;
hdma_spi_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK) return false;
__HAL_LINKDMA(&hspi,hdmatx,hdma_spi_tx);
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
And this is the code that runs on the master:
unsigned int bitsPerByte = 8u;
unsigned int delay = 0u;
unsigned int speed = 100; // hz
unsigned int cs_change = 0u; // false in C
// initialization
fd = ::open("/dev/spidev0.0", O_RDWR);
auto mode = SPI_MODE_2; // clock polarity low, clock phase second edge
if (fd == -1)
throw std::runtime_error("Can't open the spi device");
if (::ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1)
throw std::runtime_error("Can't set the spi mode");
/*
* bits per word
*/
auto bits = bitsPerByte;
auto ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
throw std::runtime_error("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
throw std::runtime_error("can't get bits per word");
/*
* max speed hz
*/
auto maxSpeed = speed;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);
if (ret == -1)
throw std::runtime_error("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &maxSpeed);
if (ret == -1)
throw std::runtime_error("can't get max speed hz");
// code used for sending messages
void transfer(uint8_t *tx, uint8_t *rx, size_t size) {
struct spi_ioc_transfer tr = {
(unsigned long)tx, // .tx_buf
(unsigned long)rx, // .rx_buf
size, // .len
speed, // .speed_hz
delay, // .delay_usecs
bitsPerByte, // .bits_per_word
cs_change, // .cs_change
0, // .tx_nbits
0, // .rx_nbits
0, // .pad
};
if (::ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == -1)
throw std::runtime_error("Can't send data throught the spi");
}
In the main functions of the slaves the only thing that I actually do is to send back the exact packet that I receive.
EDIT
On the forum of the Raspberry someone told me to use piscope to see the digital value that is send on the pins. I've done it and I've seen that the CE0 and CE1 pin are always low. I can't understand why I do not have collisions on the MISO.
EDIT 2
I've solved the second problem (the duplicated data) it was an error on the master configuration, I was using cs_change = 1 but it must be equal to 0.
With piscope I've figured out that the slaves are sending the data correctly, it's the master that does not read them well.

setting up the clock on my nucleo-L432KC for a 5 channel adc conversion using DMA

So i have been trying to set up my ADC conversion on my Nucleo-L432KC and have been having a hard time. i recently have been working on a Nucleo-F303RE which is a 64 pin nucleo and my 5 channel ADC conversions using DMA where working great.
I then decided to downgrade to a nucleo-L432KC (32 pin nucleo). i used the same steps i did for the F303 but this time it doesn't work. I looked in to it a bit and found that it would never enter the HAL_ADC_ConvCpltCallback. another post talking about it What is missing to make stm32 ADC DMA work? Transfer Compete does not occur. the solution of this post says that the core clock was to slow compared to the adc conversion clock and so did not wave the time to call the function. i was looking into the clock systeme on CubeMx and have a hard time with the clock set up. the f303RE was more strait forward and this one i get kinda lost. any one have some tips on what i should change to make this work. here is the cube mx set up: voila.
here is my DMA set up:
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
and here is my adc set up:
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 5;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
//_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
//_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
//_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_10;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
//_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
//_Error_Handler(__FILE__, __LINE__);
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = ADC_REGULAR_RANK_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
//_Error_Handler(__FILE__, __LINE__);
}
}
and finally my code:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef& hadc){
if(hadc.Instance == ADC1){
adc_IT_flag = 1;
}
}
void filtreRead(void){
fenGlisflex(ADC_BUF[0],flex0);
fenGlisflex(ADC_BUF[1],flex1);
fenGlisflex(ADC_BUF[2],flex2);
fenGlisflex(ADC_BUF[3],flex3);
fenGlisflex(ADC_BUF[4],flex4);
data_stable(flex0);
data_stable(flex1);
data_stable(flex2);
data_stable(flex3);
data_stable(flex4);
adc_IT_flag = 0;
HAL_ADC_Start_IT(&hadc1);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC_BUF,5);
HAL_ADC_Start_IT(&hadc1);
while (1)
{
if(adc_IT_flag){
filtreRead();
}
}
}
here is my new DMA Init function :
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.MemDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_DeInit(&hdma_adc1);
HAL_DMA_Init(&hdma_adc1);
//__HAL_LINKDMA(hadc, DMA_Handle, hdma_adc1);
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
In your MX_DMA_Init() function you are enabling the DMA IT, but you are missing the actual DMA configuration:
static void MX_DMA_Init(void)
{
/* Peripheral DMA init*/
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_NORMAL;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_DeInit(&hdma_adc1);
HAL_DMA_Init(&hdma_adc1);
__HAL_LINKDMA(hadc, DMA_Handle, hdma_adc1);
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
EDIT: a few other things
If you want to use DMA, you should call HAL_ADC_Start_DMA() but not HAL_ADC_Start_IT().
If missing you should also add the handler into stm32xxxx_it.c file
void DMA1_Channel1_IRQHandler(void)
{
/* Calling the peripheral interrupt handler */
HAL_DMA_IRQHandler(&hdma_adc1);
}
I also suggest to use a 4-bytes multiple length for the DMA.
So i found the problem. The HAL functions for DMA interrupts don't work in c++. I had converted my project in C++ and it wouldn't work as for the version that I made with the Nucleo-F303RE was in C. when i converted it to c++ it stopped working also.
EDIT:
wow you will never guess what the error was.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef& hadc){
if(hadc.Instance == ADC1){
adc_IT_flag = 1;
}
}
should actually be:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
if(hadc.Instance == ADC1){
adc_IT_flag = 1;
}
}
the interrupt function wouldn't get called because of the pointer

Send cmd to SD card but error 22 on Linux

I refer an article:
Any way to send commands to SD card from Linux userspace?
and use the source of mmc-util to send cmd to SD card, there is the code:
int cmd_test(int fd, __u8 *ext_csd)
{
int ret = 0;
struct mmc_ioc_cmd idata;
memset(&idata, 0, sizeof(idata));
memset(ext_csd, 0, sizeof(__u8) * 512);
idata.write_flag = 0;
idata.opcode = 17;
idata.arg = 0;
idata.flags = MMC_DATA_READ;
idata.blksz = 512;
idata.blocks = 1;
mmc_ioc_cmd_set_data(idata, ext_csd);
ret = ioctl(fd, MMC_IOC_CMD, &idata);
if (ret)
perror("ioctl");
return ret;
}
finally receive error 22: invalid argument. I try another opcode like 10, 56..., it finally result same error.
The SD card is connected by usb reader, does it cause the error? or there are parameter setting error?
Thanks.