avr codevision issue getting acknowledge or TX_DS flag in nRF24L01+ MODULE - module

I am trying to communicate using two nRF24L01 radio modules connected to atmega8s over spi.
All I can do is to write some register of the nRF, but no data can be sent. When I read the radio status register it returns decimal 14 or sometimes 0 or sometimes decimal 30.
Here is my atmega8 code:
#include <mega8.h>
#include <C:\cvavr\BIN\nRF24L01\nrf24l012.h>
#include <stdio.h>
#include <pcf8576d.h>
#define _CH 1 // Channel 0..125
#define _Address_Width 5 // 3..5
#define _Buffer_Size 32 // 1..32
// Declare your global variables here
unsigned char global_var=0;
void NRF24L01_Receive(char Buf[_Buffer_Size]) {
NRF24L01_CE_HIGH;
delay_us(130);
while ((NRF24L01_Get_Status() & _RX_DR) != _RX_DR);
NRF24L01_CE_LOW;
NRF24L01_Read_RX_Buf(Buf, _Buffer_Size);
NRF24L01_Clear_Interrupts();
}
void NRF24L01_Send(char* Buf) {
NRF24L01_Write_TX_Buf(Buf, _Buffer_Size);
NRF24L01_RF_TX();
while ((NRF24L01_Get_Status() & _TX_DS) != _TX_DS) ;
NRF24L01_Clear_Interrupts();
}
// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
char buffer[32];
char state = NRF24L01_Get_Status();
lcd_erase();
lcd_printf("INT ");
lcd_print(state);
if(state==0) NRF24L01_Read_RX_Buf(buffer,32);
lcd_print(buffer[0]);
delay_ms(100);
NRF24L01_Clear_Interrupts();
}
// SPI interrupt service routine
interrupt [SPI_STC] void spi_isr(void)
{
}
void main(void)
{
// Declare your local variables here
char i;
unsigned char bffr[5];
unsigned char Buf[_Buffer_Size];
unsigned char Data[5]={3,9,5,8,4};
unsigned char Address_p0[_Address_Width] = { 0xf0,0xf0,0xf0,0xf0,0xe1 };
unsigned char Address_p1[_Address_Width] = { 0xf0,0xf0,0xf0,0xf0,0xd2 };
unsigned char Address_p2[1]={0xc3};
unsigned char Address_p3[1]={0xc4};
unsigned char Address_p4[1]={0xc5};
unsigned char Address_p5[1]={0xc6};
spi_int1_init();
TWI_init_master();
delay_ms(300);
lcd_erase();
lcd_printf("start");
delay_ms(1200);
NRF24L01_Init(_TX_MODE, _CH, _1Mbps, Address_p0, _Address_Width, _Buffer_Size);
NRF24L01_WriteReg(W_REGISTER | EN_RXADDR,0x03);
NRF24L01_Set_RX_Pipe (0,Address_p0,_Address_Width, _Buffer_Size);
NRF24L01_Set_RX_Pipe (1,Address_p1,_Address_Width, _Buffer_Size);
NRF24L01_Set_TX_Address(Address_p0,_Address_Width);
NRF24L01_Set_RX_Pipe (2,Address_p2,1,0);
NRF24L01_Set_RX_Pipe (3,Address_p3,1,0);
NRF24L01_Set_RX_Pipe (4,Address_p4,1,0);
NRF24L01_Set_RX_Pipe (5,Address_p5,1,0);
NRF24L01_WriteReg(W_REGISTER | EN_AA,0X3F);
NRF24L01_WriteReg(W_REGISTER | EN_RXADDR,0x03);
NRF24L01_WriteReg(W_REGISTER | RF_CH, 0x0c);
NRF24L01_WriteReg(W_REGISTER | RF_SETUP,0X03);
NRF24L01_WriteReg(W_REGISTER | CONFIG,0X0E);
NRF24L01_WriteReg(W_REGISTER | SETUP_RETR,0X28);
global_var = NRF24L01_Get_Status();
//global_var=SPI(234);
lcd_erase();
lcd_print(global_var);
delay_ms(1000);
global_var = NRF24L01_ReadReg(CONFIG);
lcd_erase();
lcd_print(global_var);
delay_ms(1000);
lcd_erase();
NRF24L01_ReadRegBuf(TX_ADDR,bffr,5);
for(i=0;i<5;i++)
lcd_print(bffr[i]);
delay_ms(1000);
global_var = NRF24L01_ReadReg(FIFO_STATUS);
lcd_erase();
lcd_printf("ffo ");
lcd_print(global_var);
delay_ms(1000);
NRF24L01_Send(Data);
global_var = NRF24L01_Get_Status();
lcd_erase();
lcd_print(global_var);
delay_ms(1000);
global_var = NRF24L01_ReadReg(FIFO_STATUS);
lcd_erase();
lcd_printf("mioh ");
lcd_print(global_var);
delay_ms(1000);
while (1);
}
and here is my nrf24l012.h
#include <delay.h>
#include <C:\cvavr\BIN\nRF24L01\nrf24l011.h>
/*
* SPI pins:
* MOSI: DDB3
* MISO: DDB4
* SCK : DDB5
* CSN : DDB2
* CE : DDB1
*/
void spi_int1_init(void){
// Input/Output Ports initialization
// Port B initialization
// Function: Bit7=In Bit6=In Bit5=Out Bit4=In Bit3=Out Bit2=Out Bit1=In Bit0=In
DDRB=(0<<DDB7) | (0<<DDB6) | (1<<DDB5) | (0<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=0 Bit4=T Bit3=0 Bit2=0 Bit1=T Bit0=T
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);
// External Interrupt(s) initialization
// INT0: Off
// INT1: On
// INT1 Mode: Falling Edge
GICR|=(1<<INT1) | (0<<INT0);
MCUCR=(1<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
GIFR=(1<<INTF1) | (0<<INTF0);
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 2000.000 kHz
// SPI Clock Phase: Cycle Start
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=(1<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
SPSR=(0<<SPI2X);
// Clear the SPI interrupt flag
#asm
in r30,spsr
in r30,spdr
#endasm
// Global enable interrupts
#asm("sei")
}
//Function to send and receive data for both master and slave
unsigned char SPI(unsigned char data)
{
// Load data into the buffer
SPDR = data;
//Wait until transmission complete
while(!(SPSR & (1<<SPIF) ));
SPSR = (1<<SPIF);
// Return received data
return(SPDR);
}
/* CE is set to output */
#define NRF24L01_CE_OUT DDRB |= (1<<DDB1) ;
#define NRF24L01_CE_HIGH PORTB |= (1<<DDB1) ;
#define NRF24L01_CE_LOW PORTB &= ~(1<<DDB1);
#define NRF24L01_CSN_HIGH PORTB |= (1<<DDB2) ;
#define NRF24L01_CSN_LOW PORTB &= ~(1<<DDB2);
/**
Read a register
#param Reg Register to read
#return Registry Value
*/
char NRF24L01_ReadReg(char Reg) {
char Result;
NRF24L01_CSN_LOW;
SPI(Reg);
Result = SPI(NOP); // "NOP" in here just roles as a dummy data byte nothing more.
NRF24L01_CSN_HIGH;
return Result;
}
/**
Returns the STATUS register and then modify a register
#param Reg Register to change
#param Value New value
#return STATUS Register
*/
char NRF24L01_WriteReg(char Reg, char Value) {
char Result;
NRF24L01_CSN_LOW;
Result = SPI(Reg);
SPI(Value);
NRF24L01_CSN_HIGH;
return Result;
}
/**
Returns the STATUS register and then read "n" registers
#param Reg Register to read
#param Buf Pointer to a buffer
#param Size Buffer Size
#return STATUS Register
*/
char NRF24L01_ReadRegBuf(char Reg, char *Buf, int Size) {
int i;
char Result;
NRF24L01_CSN_LOW;
Result = SPI(Reg);
for (i = 0; i < Size; i++) {
Buf[i] = SPI(NOP);
}
NRF24L01_CSN_HIGH;
return Result;
}
/**
Returns the STATUS register and then write "n" registers
#param Reg Registers to change
#param Buf Pointer to a buffer
#param Size Buffer Size
#return STATUS Register
*/
char NRF24L01_WriteRegBuf(char Reg, char *Buf, int Size) {
int i;
char Result;
NRF24L01_CSN_LOW;
Result = SPI(Reg);
for (i = 0; i < Size; i++) {
SPI(Buf[i]);
}
NRF24L01_CSN_HIGH;
return Result;
}
/**
Returns the STATUS register
#return STATUS Register
*/
char NRF24L01_Get_Status(void) {
char Result;
NRF24L01_CSN_LOW;
Result = SPI(NOP);
NRF24L01_CSN_HIGH;
return Result;
}
/**
Returns the carrier signal in RX mode (high when detected)
#return CD
*/
char NRF24L01_Get_CD(void) {
return (NRF24L01_ReadReg(CD) & 1);
}
/**
Select power mode
#param Mode = _POWER_DOWN, _POWER_UP
#see _POWER_DOWN
#see _POWER_UP
*/
void NRF24L01_Set_Power(char Mode) {
char Result;
Result = NRF24L01_ReadReg(CONFIG) & 0b01111101; // Read Conf. Reg. AND Clear bit 1 (PWR_UP) and 7 (Reserved)
NRF24L01_WriteReg(W_REGISTER | CONFIG, Result | Mode);
}
/**
Select the radio channel
#param CH = 0..125
*/
void NRF24L01_Set_CH(char CH) {
NRF24L01_WriteReg(W_REGISTER | RF_CH, (CH & 0b01111111)); // Clear bit 8
}
/**
Select Enhanced ShockBurst ON/OFF
Disable this functionality to be compatible with nRF2401
#param Mode = _ShockBurst_ON, _ShockBurst_OFF
#see _ShockBurst_ON
#see _ShockBurst_OFF
*/
void NRF24L01_Set_ShockBurst(char Mode) {
NRF24L01_WriteReg(W_REGISTER | SETUP_RETR, Mode);
NRF24L01_WriteReg(W_REGISTER | EN_AA, Mode);
}
/**
Select the address width
#param Width = 3..5
*/
void NRF24L01_Set_Address_Width(char Width) {
NRF24L01_WriteReg(W_REGISTER | SETUP_AW, (Width - 2)); // orginal was (Width & 3) -2) but is incorrect
}
/**
Select mode receiver or transmitter
#param Device_Mode = _TX_MODE, _RX_MODE
#see _TX_MODE
#see _RX_MODE
*/
void NRF24L01_Set_Device_Mode(char Device_Mode) {
char Result;
Result = NRF24L01_ReadReg(CONFIG) & 0b01111110; // Read Conf. Reg. AND Clear bit 0 (PRIM_RX) and 7 (Reserved)
NRF24L01_WriteReg(W_REGISTER | CONFIG, Result | Device_Mode);
}
/**
Enables and configures the pipe receiving the data
#param PipeNum Number of pipe
#param Address Address
#param AddressSize Address size
#param PayloadSize Buffer size, data receiver
*/
void NRF24L01_Set_RX_Pipe(char PipeNum, char *Address, int AddressSize, char PayloadSize) {
char Result;
Result = NRF24L01_ReadReg(EN_RXADDR);
NRF24L01_WriteReg(W_REGISTER | EN_RXADDR, Result | (1 << PipeNum));
NRF24L01_WriteReg(W_REGISTER | (RX_PW_P0 + PipeNum), PayloadSize);
NRF24L01_WriteRegBuf(W_REGISTER | (RX_ADDR_P0 + PipeNum), Address, AddressSize);
}
/**
Disable all pipes
*/
void NRF24L01_Disable_All_Pipes(void) {
NRF24L01_WriteReg(W_REGISTER | EN_RXADDR, 0);
}
/** Returns the STATUS register and then clear all interrupts
*
* #return STATUS Register
*/
char NRF24L01_Clear_Interrupts(void) {
return NRF24L01_WriteReg(W_REGISTER | STATUS, _RX_DR | _TX_DS | _MAX_RT);
}
/**
Sets the direction of transmission
#param Address Address
#param Size Address size 3..5
*/
void NRF24L01_Set_TX_Address(char *Address, int Size) {
NRF24L01_WriteRegBuf(W_REGISTER | TX_ADDR, Address, Size);
}
/**
Empty the transmit buffer
*/
void NRF24L01_Flush_TX(void) {
NRF24L01_CSN_LOW;
SPI(FLUSH_TX);
NRF24L01_CSN_HIGH;
}
/**
Empty the receive buffer
*/
void NRF24L01_Flush_RX(void) {
NRF24L01_CSN_LOW;
SPI(FLUSH_RX);
NRF24L01_CSN_HIGH;
}
/**
Initializes the device
#param Device_Mode = _TX_MODE, _RX_MODE
#param CH = 0..125
#param DataRate = _1Mbps, _2Mbps
#param Address Address
#param Address_Width Width direction: 3..5
#param Size_Payload Data buffer size
#see _TX_MODE
#see _RX_MODE
#see _1Mbps
#see _2Mbps
*/
void NRF24L01_Init(char Device_Mode, char CH, char DataRate,
char *Address, char Address_Width, char Size_Payload) {
NRF24L01_CE_OUT; // Set Port DIR out
// Enable Enhanced ShockBurst....._ShockBurst_OFF
NRF24L01_Set_ShockBurst(_ShockBurst_ON);
// RF output power in TX mode = 0dBm (Max.)
// Set LNA gain
NRF24L01_WriteReg(W_REGISTER | RF_SETUP, 0b00000111 | DataRate);
NRF24L01_Set_Address_Width(Address_Width);
NRF24L01_Set_RX_Pipe(0, Address, Address_Width, Size_Payload);
NRF24L01_Set_CH(CH);
NRF24L01_Set_TX_Address(Address, Address_Width); // Set Transmit address
// Bits 4..6: Reflect interrupts as active low on the IRQ pin
// Bit 3: Enable CRC
// Bit 2: CRC 1 Byte
// Bit 1: Power Up
NRF24L01_WriteReg(W_REGISTER | CONFIG, 0b00001010 | Device_Mode);
delay_us(1500);
}
/**
Turn on transmitter, and transmits the data loaded into the buffer
*/
void NRF24L01_RF_TX(void) {
NRF24L01_CE_LOW;
NRF24L01_CE_HIGH;
delay_us(10);
NRF24L01_CE_LOW;
}
/**
Writes the buffer of data transmission
#param Buf Buffer with data to send
#param Size Buffer size
*/
void NRF24L01_Write_TX_Buf(char *Buf, int Size) {
NRF24L01_WriteRegBuf(W_REGISTER | W_TX_PAYLOAD, Buf, Size);
}
/**
Read the data reception buffer
#param Buf Buffer with data received
#param Size Buffer size
*/
void NRF24L01_Read_RX_Buf(char *Buf, int Size) {
NRF24L01_ReadRegBuf(R_RX_PAYLOAD, Buf, Size);
}
i can not understand what is the problem..
please help me thanks?!
AND HERE IS nrf24l01+.h definition
/*
* #author
* Copyright (C) 2012 Luis R. Hilario http://www.luisdigital.com
*
*/
// Bits
/**
* Data Ready RX FIFO interrupt
*/
#define _RX_DR (1<<6)
/**
* Data Sent TX FIFO interrupt
*/
#define _TX_DS (1<<5)
/**
* Maximum number of TX retransmits interrupt
*/
#define _MAX_RT (1<<4)
/** Power Down mode
*
* Minimal current consumption, SPI can be activated
*
* #see NRF24L01_Set_Power(char Mode)
*/
#define _POWER_DOWN 0
/** Power Up mode
*
* Standby-I mode
*
* #see NRF24L01_Set_Power(char Mode)
*/
#define _POWER_UP (1<<1)
/** Mode radio transmitter
*
* #see NRF24L01_Set_Device_Mode(char Device_Mode)
* #see NRF24L01_Init(char Device_Mode, char CH, char DataRate,
char *Address, char Address_Width, char Size_Payload)
*/
#define _TX_MODE 0
/** Mode radio receiver
*
* #see NRF24L01_Set_Device_Mode(char Device_Mode)
* #see NRF24L01_Init(char Device_Mode, char CH, char DataRate,
char *Address, char Address_Width, char Size_Payload)
*/
#define _RX_MODE 1
/** Air data rate = 1 Mbps
*
*
* #see NRF24L01_Init(char Device_Mode, char CH, char DataRate,
char *Address, char Address_Width, char Size_Payload)
*/
#define _1Mbps 0
/** Air data rate = 2 Mbps
*
* #see NRF24L01_Init(char Device_Mode, char CH, char DataRate,
char *Address, char Address_Width, char Size_Payload)
*/
#define _2Mbps (1<<3)
/** Enable ShockBurst
Automatic Retransmission (Up to 1 Re-Transmit on fail of AA)
Auto Acknowledgment (data pipe 0)
#see NRF24L01_Set_ShockBurst(char Mode)
*/
#define _ShockBurst_ON 1
/** Disable ShockBurst
*
#see NRF24L01_Set_ShockBurst(char Mode)
*/
#define _ShockBurst_OFF 0
// REGISTERS
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
#define DYNPD 0x1C
#define FEATURE 0x1D
// COMMANDS
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define ACTIVATE 0x50
#define R_RX_PL_WID 0x60
#define W_ACK_PAYLOAD 0xA8
#define W_TX_PAYLOAD_NOACK 0x58
#define NOP 0xFF
/*
* SPI functions for NRF24L01
*/
char NRF24L01_ReadReg(char Reg);
char NRF24L01_WriteReg(char Reg, char Value);
char NRF24L01_ReadRegBuf(char Reg, char *Buf, int Size);
char NRF24L01_WriteRegBuf(char Reg, char *Buf, int Size);
/*
* NRF24L01 functions
*/
char NRF24L01_Get_Status(void);
char NRF24L01_Get_CD(void);
void NRF24L01_Set_Power(char Mode);
void NRF24L01_Set_CH(char CH);
void NRF24L01_Set_ShockBurst(char Mode);
void NRF24L01_Set_Address_Width(char Width);
void NRF24L01_Set_Device_Mode(char Device_Mode);
void NRF24L01_Set_RX_Pipe(char PipeNum, char *Address, int AddressSize, char PayloadSize);
void NRF24L01_Disable_All_Pipes(void);
char NRF24L01_Clear_Interrupts(void);
void NRF24L01_Set_TX_Address(char *Address, int Size);
void NRF24L01_Flush_TX(void);
void NRF24L01_Flush_RX(void);
void NRF24L01_Init(char Device_Mode, char CH, char DataRate,
char *Address, char Address_Width, char Size_Payload);
void NRF24L01_RF_TX(void);
void NRF24L01_Write_TX_Buf(char *Buf, int Size);
void NRF24L01_Read_RX_Buf(char *Buf, int Size);

hello friends succesfully i get it and i was able to send data over nrf24l01+ module to another nrf24l01+ module for this i used an ATMEGA16A as TX and an ATmega8a as RX(receiver) controller:
i used the code in this link written by some good people and it works perfectly but i need to change som i/o port to be compitable with Atmega8 for receiver module .
as i compare my last code with this one i understand that i changed rx and tx Adresses and in this code (works well) nothing is changed related to Adresses of module and left to its default values..
so my fault was manipulating adresses incorrectly..
here is the link to code works good..
UPDATE: as i revisited my code to see whats problem i understand the whole problem was from nrf24l01.h file that declared a function misdingushly it sends W_TX_PAYLOAD ORing with W_REGISTER while such an adress is not exist in nrf so the whole process is got wrong..
error was in declaring :
'NRF24L01_Write_TX_Buf ' function
in line:
NRF24L01_WriteRegBuf(W_REGISTER | W_TX_PAYLOAD, Buf, Size);
while this is wrong and must be Corrected as:
NRF24L01_WriteRegBuf(W_TX_PAYLOAD, Buf, Size);
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
http://www.avrfreaks.net/forum/nrf24l01-problem-communication-failure-cannot-even-read-registers-data-atmega16a

Related

STM32 SPI communication with HAL

I just started programming a STM32 and generated a code with CubeMX for an SPI communcation with a gyroscope (L3GD20)
I have a problem with the HAL_SPI commands.
I first try to read the WHO_AM_I register which return a good response (0xD4)
Then I tried to do the same with CTRL_REG1 register and it was still good by returning (0x07).
But if I try to get both of them one after the other, the HAL_SPI_Receive keeps sending the data of the first HAL_SPI_Transmit of the code...
Tried to give it other buffers but still didn't work.
Here is the part of the code I'm intersted in :
uint8_t txData[8],rxData[8]; //Buffers for the first read.
uint8_t rBuffer[8]; //Buffer for the second read.
/*...............................................................
*...............................................................
*...............................................................
*/...............................................................
txData[0] = ADDR_WHO_AM_I | 0x80;
HAL_SPI_Transmit(&hspi2, txData, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi2, rxData, 1, HAL_MAX_DELAY); //Returns the right value
HAL_Delay(1000);
txData[0] = ADDR_CTRL_REG1 | 0x80;
HAL_Delay(500);
HAL_SPI_Transmit(&hspi2, txData, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi2, rBuffer, 1, HAL_MAX_DELAY); //Returns the same value...
HAL_Delay(1000);
PS : I also would like to know more about HAL_SPI_TransmitReceive if possible, how should I use it to perform the same task ? (Reading 1 byte from different registers).
There is the full code too :
/**
******************************************************************************
* #file : main.c
* #brief : Main program body
******************************************************************************
* #attention
*
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
// Gyro Definitions
#define ADDR_WHO_AM_I 0x0f
#define ADDR_CTRL_REG1 0x20
#define ADDR_CTRL_REG2 0x21
#define ADDR_CTRL_REG3 0x22
#define ADDR_CTRL_REG4 0x23
#define ADDR_CTRL_REG5 0x24
#define ADDR_OUT_TEMP 0x26
#define ADDR_STATUS_REG 0x27
#define ADDR_OUT_X_L 0x28
#define ADDR_OUT_X_H 0x29
#define ADDR_OUT_Y_L 0x2A
#define ADDR_OUT_Y_H 0x2B
#define ADDR_OUT_Z_L 0x2C
#define ADDR_OUT_Z_H 0x2D
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c3;
SD_HandleTypeDef hsd1;
SPI_HandleTypeDef hspi2;
/* USER CODE BEGIN PV */
HAL_SD_CardInfoTypeDef pCardInfo;
char datar[1024];
HAL_StatusTypeDef retstat;
//HAL_MMC_CardInfoTypeDef pCardInfo;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SDMMC1_SD_Init(void);
static void MX_I2C3_Init(void);
static void MX_SPI2_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* #brief The application entry point.
* #retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
int ret;
uint8_t txData[8],rxData[8]; //Buffers for the first read.
uint8_t rBuffer[8]; //Buffer for the second read.
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDMMC1_SD_Init();
MX_I2C3_Init();
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
txData[0] = ADDR_WHO_AM_I | 0x80;
HAL_SPI_Transmit(&hspi2, txData, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi2, rxData, 1, HAL_MAX_DELAY);
HAL_Delay(1000);
txData[0] = ADDR_CTRL_REG1 | 0x80;
HAL_Delay(500);
HAL_SPI_Transmit(&hspi2, txData, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(&hspi2, rBuffer, 1, HAL_MAX_DELAY);
HAL_Delay(1000);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV4;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C3|RCC_PERIPHCLK_SDMMC1;
PeriphClkInit.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1;
PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/** Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
}
/**
* #brief I2C3 Initialization Function
* #param None
* #retval None
*/
static void MX_I2C3_Init(void)
{
/* USER CODE BEGIN I2C3_Init 0 */
/* USER CODE END I2C3_Init 0 */
/* USER CODE BEGIN I2C3_Init 1 */
/* USER CODE END I2C3_Init 1 */
hi2c3.Instance = I2C3;
hi2c3.Init.Timing = 0x10909CEC;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C3_Init 2 */
/* USER CODE END I2C3_Init 2 */
}
/**
* #brief SDMMC1 Initialization Function
* #param None
* #retval None
*/
static void MX_SDMMC1_SD_Init(void)
{
/* USER CODE BEGIN SDMMC1_Init 0 */
/* USER CODE END SDMMC1_Init 0 */
/* USER CODE BEGIN SDMMC1_Init 1 */
/* USER CODE END SDMMC1_Init 1 */
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_1B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
hsd1.Init.ClockDiv = 0;
if (HAL_SD_Init(&hsd1) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SDMMC1_Init 2 */
//HAL_StatusTypeDef HAL_MMC_GetCardInfo(MMC_HandleTypeDef *hmmc, HAL_MMC_CardInfoTypeDef *pCardInfo)
/* USER CODE END SDMMC1_Init 2 */
}
/**
* #brief SPI2 Initialization Function
* #param None
* #retval None
*/
static void MX_SPI2_Init(void)
{
/* USER CODE BEGIN SPI2_Init 0 */
/* USER CODE END SPI2_Init 0 */
/* USER CODE BEGIN SPI2_Init 1 */
/* USER CODE END SPI2_Init 1 */
/* SPI2 parameter configuration*/
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 7;
hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI2_Init 2 */
/* USER CODE END SPI2_Init 2 */
}
/**
* #brief GPIO Initialization Function
* #param None
* #retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1|GPIO_PIN_0, GPIO_PIN_RESET);
/*Configure GPIO pins : PE1 PE0 */
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
I can't explain the behavior you described for the separate HAL_SPI_Transmit() and HAL_SPI_Receive() calls. But regardless, you should be using HAL_SPI_TransmitReceive(). Here is an example.
HAL_StatusTypeDef ReadRegister(uint8_t addr, uint8_t *byte)
{
HAL_StatusTypeDef hal_status;
uint8_t tx_data[2];
uint8_t rx_data[2];
tx_data[0] = addr | 0x80; // read operation
tx_data[1] = 0; // dummy byte for response
hal_status = HAL_SPI_TransmitReceive(&hspi2, tx_data, rx_data, 2, SPI_TIMEOUT);
if (hal_status == HAL_OK)
{
*byte = rx_data[1]; // response is in the second byte
}
return hal_status;
}
The master SPI controller clocks out bytes and both the master and slave transmit and receive during each byte. For the first byte, the master transmits the register addr and the slave transmits a dummy byte because the slave doesn't know what register you're trying to read yet. (Some slave devices send a status in the first byte.) For the second byte, the master transmits a dummy byte for the purpose of generating more clocks on which the slave can respond. After receiving the register address during the first byte, the slave knows which register value to transmit during the second byte. Notice in the example code that the received byte you're interested in is the second byte of the response buffer.
Since HAL_SPI_Receive is already using HAL_SPI_TransmitReceive (github stm32f4 spi driver) to send dummy data to generate clock, you can use that fact and ditch the HAL_SPI_Transmit, and use the receive function like this:
rxData[0] = ADDR_WHO_AM_I | 0x80;
HAL_SPI_Receive(&hspi2, rxData, 1, HAL_MAX_DELAY);
Note that we provide the address and operation using rxData but it will effectively be overwritten by the read data.
or you can simply use HAL_SPI_TransmitReceive :
txData[0] = ADDR_WHO_AM_I | 0x80;
HAL_SPI_TransmitReceive(&hspi2, txData, rxData, 1, HAL_MAX_DELAY);
HAL_Delay(500);
txData[0] = ADDR_CTRL_REG1 | 0x80;
HAL_SPI_TransmitReceive(&hspi2, txData, rxData, 1, HAL_MAX_DELAY);

how to configure MAX11140 (ADC converter) With STM32F401RET? (SPI protocol)

THIS IS THE LINK OF THE DATASHEET
https://www.mouser.in/datasheet/2/256/MAX11135-MAX11143-220131.pdf
HERE IS MY CODE
/**
******************************************************************************
* #file : main.c
* #brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2019 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint16_t adc_config_reg=0b1000000000000100;
uint16_t unipolar_reg = 0b1000100000000000;
uint16_t bipolar_reg = 0b1001000000000000;
uint16_t adc_mode_reg = 0b0000100010000100;
uint16_t rx_adc_config_reg;
uint16_t rx_unipolar_reg;
uint16_t rx_bipolar_reg;
uint16_t rx_adc_mode_reg;
//uint16_t rx_adc_mode_reg1[16];
uint16_t rx[16];
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* #brief The application entry point.
*
* #retval None
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SPI1_Init();
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&adc_config_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Receive(&hspi1,&rx_adc_config_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
//
// HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
//
// HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&unipolar_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Receive(&hspi1,&rx_unipolar_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&bipolar_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Receive(&hspi1,&rx_bipolar_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&adc_mode_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
// HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
// HAL_SPI_Receive(&hspi1,&rx_adc_mode_reg,1,100);
// HAL_SPI_Transmit(&hspi1,&adc_mode_reg1,1,100);
// HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
//
// HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
// HAL_SPI_Receive(&hspi1,&rx_adc_mode_reg,1,100);
// HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);
HAL_SPI_Receive(&hspi1,&rx_adc_mode_reg,1,100);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
HAL_Delay(2);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* SPI1 init function */
static void MX_SPI1_Init(void)
{
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
/*Configure GPIO pin : PB6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #param file: The file name as string.
* #param line: The line in file as a number.
* #retval None
*/
void _Error_Handler(char *file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/**
* #}
*/
/**
* #}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
I have configured With Cubmx
Data Size 16 bit
CPOL=CPHA= 1
first bit = MSB
MY SPI COMMUNICATION IS COMPLETE
I AM HAVING TROUBLE RECEIVING OUTPUT DATA AFTER CONVERSION

Defining buffer size in Linux kernel module by parameter

I need to change the buffer size in the character device by parameter, so that, for example, when I write
insmod chardev.ko len=6
echo "Have a nice day!" > /dev/chardev.ko
cat /dev/chardev.ko
My output would be:
Have a
I've simply tried to replace the msg[BUF_SIZE] by msg[len], but I receive an error 'variably modified at file scope'.
I have no idea how to proceed. Any hints?
Here's the code:
/*
* chardev.c: Creates a read-only char device that says how many times
* you've read from the dev file
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* for put_user */
/*
* Prototypes - this would normally go in a .h file
*/
int init_module(void);
void cleanup_module(void);
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static int len=100;
module_param(len, int, S_IRUGO);
MODULE_PARM_DESC(len, "The length of buffer");
#define SUCCESS 0
#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */
#define BUF_LEN 100
/*
* Global variables are declared as static, so are global within the file.
*/
static int Major; /* Major number assigned to our device driver */
static int Device_Open = 0; /* Is device open?
* Used to prevent multiple access to device */
static char msg[BUF_LEN]; /* The msg the device will give when asked */
static char *msg_Ptr;
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
/*
* This function is called when the module is loaded
*/
int init_module(void)
{
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {
printk(KERN_ALERT "Registering char device failed with %d\n", Major);
return Major;
}
printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
printk(KERN_INFO "the driver, create a dev file with\n");
printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major);
// minor numbers are used to differentiate multiple instances of a
// device that use the same driver.
printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
printk(KERN_INFO "the device file.\n");
printk(KERN_INFO "Remove the device file and module when done.\n");
return SUCCESS;
}
/*
* This function is called when the module is unloaded
*/
void cleanup_module(void)
{
/*
* Unregister the device
*/
#if 0
int ret = unregister_chrdev(Major, DEVICE_NAME);
if (ret < 0)
printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret);
#endif
unregister_chrdev(Major, DEVICE_NAME);
}
/*
* Methods
*/
/*
* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
/*
* Called when a process closes the device file.
*/
static int device_release(struct inode *inode, struct file *file)
{
Device_Open--; /* We're now ready for our next caller */
/*
* Decrement the usage count, or else once you opened the file, you'll
* never get get rid of the module.
*/
module_put(THIS_MODULE);
return 0;
}
/*
* Called when a process, which already opened the dev file, attempts to
* read from it.
*/
static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */
char *buffer, /* buffer to fill with data */
size_t length, /* length of the buffer */
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
/*
* If we're at the end of the message,
* return 0 signifying end of file
*/
if (*msg_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
while (length && *msg_Ptr) {
/*
* The buffer is in the user data segment, not the kernel
* segment so "*" assignment won't work. We have to use
* put_user which copies data from the kernel data segment to
* the user data segment.
*/
put_user(*(msg_Ptr++), buffer++);
length--;
bytes_read++;
}
/*
* Most read functions return the number of bytes put into the buffer
*/
return bytes_read;
}
/*
* Called when a process writes to dev file: echo "hi" > /dev/hello
*/
static ssize_t
device_write(struct file *filp, const char *buffer, size_t length, loff_t * off)
{
int i;
#ifdef DEBUG
printk(KERN_INFO "device_write(%p,%s,%d", file, buffer, length)
#endif // DEBUG
for(i=0; (i<length && i<BUF_LEN) || i<len; i++)
{
get_user(msg[i], buffer+i);
}
msg_Ptr=msg;
return i;
}
https://pastebin.com/wQP9p42G
Thanks in advance!

Why does UART transmit interrupt fail to work in this case?

I am using stm32f0 MCU.
I have a simple UART echo code in which every byte received will be transmitted out. I tested that it works. Here it is;
uint8_t Rx_data[5];
uint32_t tx_timeout = 0;
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) //current UART
{
HAL_UART_Transmit(&huart1, &Rx_data[0], 1, tx_timeout);
HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte
}
}
I do not feel comfortable with the code even though it works. Firstly, tx_timeout is 0 and most code examples are non-zero. I do not know the side effect. Secondly, HAL_UART_Transmit() is a blocking call and it is not advisable to use blocking calls inside an interrupt. So, I decided to use an interrupt for uart transmission HAL_UART_Transmit_IT()instead of a blocking call. Here is the modified code;
uint8_t Rx_data[5];
uint32_t tx_timeout = 0;
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) //current UART
{
HAL_UART_Transmit_IT(&huart1, &Rx_data[0], 1);
HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte
}
}
However, it does not work as expected. My PC transmits ASCII 12345678 to stm32. If things work as expected, the PC should be receiving 12345678 back. However, the PC receives 1357 instead. What is wrong with this code that uses HAL_UART_Transmit_IT()?
First:
As has been described in answers to your previous question null timeout just exclude wait for flag state. If you open HAL_UART_Transmit code - you will see that when you send 1 byte without timeout no any blocking state will!
Second:
It's not true method to send/receive one byte from a huge HAL's functions and their callbacks. I guess: next your question will "how i must implement parse there?". And I hope you will not insert you parse function in IRQ callback!
So generally you need buffers. And it is good idea to use cyclic buffer.
mxconstants.h:
/* USER CODE BEGIN Private defines */
/* Buffer's length must be select according to real messages frequency */
#define RXBUF_LEN 128 // must be power of 2
#define TXBUF_LEN 128 // must be power of 2
#define RXBUF_MSK (RXBUF_LEN-1)
#define TXBUF_MSK (TXBUF_LEN-1)
/* USER CODE END Private defines */
main.c:
uint8_t rx_buf[RXBUF_LEN], tx_buf[TXBUF_LEN];
/* xx_i - counter of input bytes (tx - pushed for transmit, rx - received)
xx_o - counter of output bytes (tx - transmitted, rx - parsed)
xx_e - counter of echoed bytes */
volatile uint16_t rx_i = 0, tx_o = 0;
uint16_t rx_o = 0, rx_e = 0, tx_i = 0;
volatile uint8_t tx_busy = 0;
void transmit(uint8_t byte)
{
tx_buf[TXBUF_MSK & tx_i] = byte;
tx_i++;
tx_busy = 1;
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);
}
void main(void)
{
/* Initialization code */
/* ... */
/* Enable usart 1 receive IRQ */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
for (;;) {
/* Main cycle */
while (rx_i != rx_e) {
/* echo here */
transmit(rx_buf[RXBUF_MSK & rx_e]);
rx_e++;
}
while (rx_i != rx_o) {
/* parse here */
/* ... */
rx_o++;
}
/* Power save
while (tx_busy);
HAL_UART_DeInit(&huart1);
*/
}
}
stm32f0xx_it.c:
extern uint8_t rx_buf[RXBUF_LEN], tx_buf[TXBUF_LEN];
extern volatile uint16_t rx_i, tx_o;
extern uint16_t rx_o, rx_e, tx_i;
extern volatile uint8_t tx_busy;
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if((__HAL_UART_GET_IT(&huart1, UART_IT_RXNE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RXNE) != RESET))
{
rx_buf[rx_i & RXBUF_MSK] = (uint8_t)(huart1.Instance->RDR & 0x00FF);
rx_i++;
/* Clear RXNE interrupt flag */
__HAL_UART_SEND_REQ(&huart1, UART_RXDATA_FLUSH_REQUEST);
}
if((__HAL_UART_GET_IT(&huart1, UART_IT_TXE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_TXE) != RESET))
{
if (tx_i == tx_o) {
__HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_TC);
} else {
huart1.Instance->TDR = (uint8_t)(tx_buf[TXBUF_MSK & tx_o] & (uint8_t)0xFF);
tx_o++;
}
}
if((__HAL_UART_GET_IT(&huart1, UART_IT_TC) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_TC) != RESET))
{
tx_busy = 0;
__HAL_UART_DISABLE_IT(&huart1, UART_IT_TC);
}
/* And never call default handler */
return;
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
And third!!!
And about this:
Why HAL_UART_Transmit_IT not help/work?
Because it's too slow! And if you try to count HAL_BUSY results:
uint8_t Rx_data[5];
uint32_t tx_timeout = 0;
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
static uint32_t hal_busy_counter = 0;
if (huart->Instance == USART1) //current UART
{
if (HAL_UART_Transmit_IT(&huart1, &Rx_data[0], 1) == HAL_BUSY) {
hal_busy_counter++;
}
HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte
}
}
When you pause MCU in debugger after data exchange - you will be suprised: it will be equal to count of missed chars.

Atmega 32, Program to drive motor , How to take input integer from user

I am trying to write a simple program to take input from user by hterm, when User enters "motor" & "25" the motor will rotate in 25 clockwise and 25 anticlockwise direction
//Define clock-speed and include necessary headers
#define F_CPU 1000000
#include <avr/io.h>
#include <util/delay.h>
#include <inttypes.h>
#include <avr/io.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdint.h>
#include <util/delay.h>
#include <ctype.h>
#define F_CPU 16000000UL
#define BAUD 9600UL
char cmd[40];
void uart_init(void) // initializing UART
{
UBRRH = 0;
UBRRL = ((F_CPU+BAUD*8)/(BAUD*16)-1);
UCSRC |= 0x86; // 8N1 Data
UCSRB = 0x18; // Receiving and Transmitting
}
int uart_putch(char ch, FILE *stream) // Function for sending Data to PC
{
if (ch == '\n')
uart_putch('\r', stream);
while (!(UCSRA & (1<<UDRE)));
UDR=ch;
return 0;
}
int uart_getch(FILE *stream) // Function for receiving Data from PC
{
unsigned char ch; while (!(UCSRA & (1<<RXC)));
ch=UDR;
uart_putch(ch,stream); // Echo the output back to the terminal
return (tolower(ch));
}
FILE uart_str = FDEV_SETUP_STREAM(uart_putch, uart_getch, _FDEV_SETUP_RW); // Important, not deleting
void loeschen() // Delete the String
{
int strnglen = 0;
while (strnglen < 41 && cmd[strnglen] != 0)
{
cmd[strnglen]= 0;
strnglen++;
}
}
// Define the stepping angle
// Note: Divide by 2 if you are doing half-stepping. for filter test 1.8 defult
#define MIN_STEP 1.8
/* Define an array containing values to be sent at the required Port - for Full-stepping
<first four bits> - <last four bits> = <decimal equivalent>
00000001 = 1 ; 01000000 = 4
00000100 = 4 ; 00010000 = 16
00000010 = 2 ; 00001000 = 8
00001000 = 8 ; 00100000 = 32
*/
unsigned short control_array_full[4] = {4,16,8,32};
/* Define an array containing values to be sent at the required Port - for Half-stepping
<first four bits> - <last four bits> = <decimal equivalent>
0000-1001 = 8 + 1 = 9 ; 0010-0100 = 32 + 4 =36
0000-0001 = 1 ; 0000-0100 = 4
0000-0101 = 4 + 1 = 5 ; 00010100 = 16 + 4 = 20
00000100 = 4 ; 00010000 = 16
00000110 = 4 + 2 = 6 ; 00011000 = 16+8=24
0000-0010 = ; 00-001000 = 8
0000-1010 = 8 + 2 = 10 ; 00-101000 = 40
0000-1000 = 8 ; 00-100000 = 32
*/
unsigned short control_array_half[8] = {36,4,20,16,24,8,40,32};
// Adjust this delay to control effective RPM
// Do not make it very small as rotor will not be able to move so fast
// Currently set at 100ms
void delay()
{
_delay_ms(100);
}
void move_clockwise(unsigned short revolutions){
int i=0;
for (i=0; i < (revolutions* 360 /MIN_STEP) ; i++)
{
//Note: Take modulo (%) with 8 when half-stepping and change array too
PORTD = control_array_half[i % 4];
delay();
}
}
void move_anticlockwise(unsigned short revolutions){
int i;
for (i = (revolutions* 360 /MIN_STEP); i > 0 ; i--){
//Note: Take modulo (%) with 8 when half-stepping and change array too
PORTD = control_array_half[i % 4];
delay();
}
}
int main()
{
// Enter infinte loop
// Make changes here to suit your requirements
uart_init(); // initializing UART
stdout = stdin = &uart_str; // Necessary to compare whole Strings
while(1){
scanf("%s",&cmd); // Read String from Data Register
printf ("Please enter number of motor rotation for clockwise and anticlockwise");
items_read = scanf ("%d", &numbers[i]); // Read integer for motor revolution
if(strcmp(cmd, "motor") == 0)
{
DDRD = 0b00111110; //Set PORTD 4 bits for output
//Enter number of revolutions required in brackets
move_clockwise(items_read);
move_anticlockwise(items_read);
}
DDRD = 0b00000000;
}
loeschen();
}
Now, The problem is that when I will delete these lines from main()
items_read = scanf ("%d", &numbers[i]);
scanf ("%d",&i);
& make items_read in move_clockwise(items_read); as:
move_clockwise(25);
move_anticlockwise(25);
Then when user enters "motor" then motor is running move_clockwise(25); but move_anticlockwise(25); is not running, what I would like is to take both "motor", number for clockwise and number for anticlockwise....
I would really appreciate if anyone can help me with this!
Thanks in advance!
First, in my opinion you're only clearing "cmd" in loeschen(), but you never assining any value.
Second "cmd" is NOT any type of UART dataregister.
DDRD is DataDirectionRegister D, that means you can set some pin to input or output mode.
Use PORTD to set a pin high or low, in example PORTD |= 1<<PD0; to set Port D Pin 0 to high.
I guess you prefer german documentation, because you named one function "loeschen()" ;-), so why don't you visit mikrocontroller.net AVR GCC Tutorial (UART)?
If you like more technic detailed youtube-stuff, et voila: Introduction to UART
RXT (ATMEGA16) - for example:
//////////////////////////////////////////////////////////////////////////
// Definitions
//////////////////////////////////////////////////////////////////////////
#define BAUD 9600UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
#error Baud to high
#endif
#define UART_MAX_STRING_LENGHT 20 // Max lenght
//////////////////////////////////////////////////////////////////////////
// UART-Receive-Variables
//////////////////////////////////////////////////////////////////////////
volatile uint8_t uart_str_complete = 0; // FLAG - String received
volatile uint8_t uart_str_count = 0; // Current position
volatile char uart_string[UART_MAX_STRING_LENGHT + 1] = ""; // received string
//////////////////////////////////////////////////////////////////////////
// ISR-UART
//////////////////////////////////////////////////////////////////////////
ISR(USART_RXC_vect)
{
unsigned char nextChar;
nextChar = UDR; // read data from buffer
if(uart_str_complete == 0) // UART-String is currently usen
{
if(nextChar != '\n' && nextChar != '\r' && uart_str_count < UART_MAX_STRING_LENGHT)
{
uart_string[uart_str_count] = nextChar;
uart_str_count++;
}
else
{
uart_string[uart_str_count] = '\0';
uart_str_count = 0;
uart_str_complete = 1;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Init UART
//////////////////////////////////////////////////////////////////////////
void Init_UART_Async()
{
UBRRH = UBRR_VAL >> 8;
UBRRL = UBRR_VAL & 0xFF;
UCSRB |= (1<<TXEN); // UART TX high
UCSRB |= (1<<RXEN); // UART RX high
UCSRB |= (1<<RXCIE); // UART RX Interrupt enable
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // Asynchron 8N1
sei(); // Enable interrups
}
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
int main(void)
{
Init_UART_Async();
while(1)
{
HandleCommunication(); // <-- Handle your communication ;-)
// and to some other cool stuff here
}
}
//////////////////////////////////////////////////////////////////////////
// Handle Communication
//////////////////////////////////////////////////////////////////////////
void HandleCommunication()
{
if(uart_str_complete == 1)
{
strcpy(received_string, uart_string); // copy received string
strcpy(uart_string, ""); // empty uart-string
uart_str_complete = 0; // set flag to 0
// handle your communication
}
}
After understanding how UART is working, you should check your codeparts
like "scanf("%s",&cmd);" in an console-application - that's easier to find some errors.
I hope this helps you a little, but I guess the best solution is when you're knowing what you're doing.
-Crazy