How to read data from MPU6050 using SAM4S - c

I'm trying to read information from an MPU6050 sensor using the SAM4S-EK2 dev board, with an ATSAM4SD32C microcontroler, showing the data in the on-board LCD display. However, when I try to read the data, the received value that shows up in the LCD is always the same.
What am I doing wrong?
I'm using Atmel Studio 7 with ASF version 3.32.0
Here is my current code:
#include <asf.h>
#define TWI_CLK 200000
#define ADDRESS 0x68
#define READ 0x3b
#define ILI93XX_LCD_CS 1
twi_options_t opt;
struct ili93xx_opt_t g_ili93xx_display_opt;
void configure_lcd()
{
/** Enable peripheral clock */
pmc_enable_periph_clk(ID_SMC);
/** Configure SMC interface for Lcd */
smc_set_setup_timing(SMC, ILI93XX_LCD_CS, SMC_SETUP_NWE_SETUP(2)
| SMC_SETUP_NCS_WR_SETUP(2)
| SMC_SETUP_NRD_SETUP(2)
| SMC_SETUP_NCS_RD_SETUP(2));
smc_set_pulse_timing(SMC, ILI93XX_LCD_CS, SMC_PULSE_NWE_PULSE(4)
| SMC_PULSE_NCS_WR_PULSE(4)
| SMC_PULSE_NRD_PULSE(10)
| SMC_PULSE_NCS_RD_PULSE(10));
smc_set_cycle_timing(SMC, ILI93XX_LCD_CS, SMC_CYCLE_NWE_CYCLE(10)
| SMC_CYCLE_NRD_CYCLE(22));
smc_set_mode(SMC, ILI93XX_LCD_CS, SMC_MODE_READ_MODE
| SMC_MODE_WRITE_MODE);
/** Initialize display parameter */
g_ili93xx_display_opt.ul_width = ILI93XX_LCD_WIDTH;
g_ili93xx_display_opt.ul_height = ILI93XX_LCD_HEIGHT;
g_ili93xx_display_opt.foreground_color = COLOR_BLACK;
g_ili93xx_display_opt.background_color = COLOR_WHITE;
/** Switch off backlight */
aat31xx_disable_backlight();
/** Initialize LCD */
ili93xx_init(&g_ili93xx_display_opt);
/** Set backlight level */
aat31xx_set_backlight(AAT31XX_AVG_BACKLIGHT_LEVEL);
ili93xx_set_foreground_color(COLOR_WHITE);
ili93xx_draw_filled_rectangle(0, 0, ILI93XX_LCD_WIDTH,
ILI93XX_LCD_HEIGHT);
/** Turn on LCD */
ili93xx_display_on();
ili93xx_set_cursor_position(0, 0);
}
int main (void)
{
sysclk_init();
board_init();
configure_lcd();
pio_configure(PIOB, PIO_PERIPH_B, (PIO_PB5A_TWCK1 | PIO_PB4A_TWD1), PIO_OPENDRAIN);
pmc_enable_periph_clk(ID_TWI1);
opt.master_clk = sysclk_get_peripheral_hz();
opt.speed = TWI_CLK;
twi_enable_master_mode(TWI1);
twi_master_init(TWI1, &opt);
twi_packet_t packet;
uint8_t answer[20];
answer[0]=0x00;
//pacote.addr[0] = 0x6b;
//pacote.addr_length = 1;
//pacote.buffer = &resposta;
//pacote.chip = ENDERECO_SENSOR;
//pacote.length = 1;
//
//if(twi_master_write(TWI1, &pacote) == TWI_SUCCESS)
//{
//ili93xx_set_foreground_color(COLOR_WHITE);
//ili93xx_draw_filled_rectangle(0, 0, 200, 200);
//ili93xx_set_foreground_color(COLOR_BLACK);
//ili93xx_draw_string(0, 0, "Enviou");
//}
while(1)
{
packet.addr[0] = READ;
packet.addr_length = 1;
packet.buffer = &answer;
packet.chip = ADDRESS;
packet.length = 14;
twi_master_read(TWI1, &packet);
char a[20];
int16_t b;
b = (answer[2] << 8 | answer[3]);
sprintf(a,"%i",b);
ili93xx_set_foreground_color(COLOR_WHITE);
ili93xx_draw_filled_rectangle(95, 175, 240, 200);
ili93xx_set_foreground_color(COLOR_BLACK);
ili93xx_draw_string(100, 180, a);
delay_ms(100);
}
}

Related

LoRa and Spirit1 FSK communication issues

I can send data from STM32WL55JC1 to Spirit1. However, I can't receive data from Spirit1 to STM32WL55JC1 and get interrupt from LoRa. Interrupt is always zero. The communication modulation is GFSK.
Also, I need some resources about STM32WL55JC1 and Spirit1.
Thank you.
Here are LoRa modulations parameters:
#define RF_FREQUENCY 868000000 /* Hz */
#define TX_OUTPUT_POWER 14 /* dBm */
#define FSK_FDEV 20000 /* Hz */
#define FSK_DATARATE 38400 /* bps */
#define FSK_BANDWIDTH 100000 /* Hz */
#define FSK_PREAMBLE_LENGTH 5 /* Same for Tx and Rx */
#define FSK_SYNCWORD_LENGTH 4
#define PAYLOAD_LEN 25
#define MAX_DATA_LEN 32
SUBGRF_SetBufferBaseAddress( 0x00,0x80 );
SUBGRF_SetRfFrequency(RF_FREQUENCY); //NOT THESE
SUBGRF_SetRfTxPower(TX_OUTPUT_POWER);
SUBGRF_SetStopRxTimerOnPreambleDetect(false);
ModulationParams_t modParams;
modParams.PacketType = PACKET_TYPE_GFSK;
modParams.Params.Gfsk.Bandwidth = SUBGRF_GetFskBandwidthRegValue(FSK_BANDWIDTH);
modParams.Params.Gfsk.BitRate = FSK_DATARATE;
modParams.Params.Gfsk.Fdev = FSK_FDEV;
modParams.Params.Gfsk.ModulationShaping = MOD_SHAPING_G_BT_1;
SUBGRF_SetModulationParams(&modParams);
packetParams.PacketType = PACKET_TYPE_GFSK;
packetParams.Params.Gfsk.AddrComp = RADIO_ADDRESSCOMP_FILT_OFF;
packetParams.Params.Gfsk.CrcLength = RADIO_CRC_OFF;
packetParams.Params.Gfsk.DcFree = RADIO_DC_FREE_OFF;
packetParams.Params.Gfsk.HeaderType = RADIO_PACKET_VARIABLE_LENGTH;
packetParams.Params.Gfsk.PayloadLength = PAYLOAD_LEN;
packetParams.Params.Gfsk.PreambleLength = (FSK_PREAMBLE_LENGTH << 3); //bytes to bits!!
packetParams.Params.Gfsk.PreambleMinDetect = RADIO_PREAMBLE_DETECTOR_OFF; //RADIO_PREAMBLE_DETECTOR_08_BITS;
packetParams.Params.Gfsk.SyncWordLength = (FSK_SYNCWORD_LENGTH << 3);
SUBGRF_SetPacketParams(&packetParams);
SUBGRF_SetSyncWord((uint8_t[]){0x88, 0x88, 0x88, 0x88});
//SUBGRF_SetWhiteningSeed(0x01FF);
SUBGRF_SetTxParams(RFO_LP, 14, RADIO_RAMP_40_US); //default comment
I am trying to develop a Local Sensor Network example that is in the Stm32wljc1 Library. Receive Function was added by me:
SUBGRF_SetDioIrqParams(IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, IRQ_RX_DONE | IRQ_RX_TX_TIMEOUT, IRQ_RADIO_NONE, IRQ_RADIO_NONE);
SUBGRF_SetSwitch(NULL, RFSWITCH_RX);
packetParams.Params.Gfsk.PayloadLength = 32;
SUBGRF_SetPacketParams(&packetParams);
RadioStandby();
SUBGRF_SetRx(0);
uint8_t *rLen;
SUBGRF_GetPayload(rxData,rLen,255);
SUBGRF_GetRxBufferStatus(rLen,rxData);
uint8_t rssiValue = SUBGRF_GetRssiInst();
uint8_t packetType = SUBGRF_GetPacketType();
SUBGRF_ClearIrqStatus(IRQ_RADIO_ALL);
HAL_Delay(100);
RadioSleep();

Configuring ATSAM3x8e port to output

I am having an issue configuring my SAM3x8e port to output, when I check the pin with a multimeter I get 1.5V so the pin 0 of Port A just isn't turning on. I believe I configured the port pins to correctly out as outputs but I do not know, I don't have a debugger on me to look at what's happening internally.
#include "sam.h"
uint32_t right_tick = 0;
uint32_t left_tick = 0;
uint32_t LED_status = 1;
void InitializeSystemTimer(void)
{
const uint32_t tickcount = 1000000;
// set value countdown restarts to
SysTick->LOAD = tickcount;
// set interrupt priority
NVIC_SetPriority(SysTick_IRQn, 3);
// restart timer
SysTick->VAL = 0;
// set system tick counter ClockSource/8, creates system tick exception when hits 0, enable system tick count,
SysTick->CTRL = SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;
}
void InitializeIOPorts(void)
{
// enable Peripheral Clock on Port A
PMC->PMC_PCER0 = ID_PIOA;
// configure output pins
// claim Port A control of pin 0, 1, 2
PIOA->PIO_PER = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// enable Port A output on pins
PIOA->PIO_WPMR = PIO_WPMR_WPKEY_Msk;
// set Port A pin 0, 1, 2 to output
PIOA->PIO_PER = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// set Port A pin 0, 1, 2 to be accessed directly by setting Output Write Enable Register
PIOA->PIO_OWER = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// set Port A pin 0, 1, 2 to high
PIOA->PIO_ODSR = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// configure input pins
// claim Port A control of pin 3, 4
PIOA->PIO_PER = PIO_PER_P3|PIO_PER_P4;
// set pull up resistors on pin 3, 4
PIOA->PIO_PUER = PIO_PER_P3|PIO_PER_P4;
// set interrupt on pin 3, 4
PIOA->PIO_IER = PIO_PER_P3|PIO_PER_P4;
// enable input change interrupt on Pin 3, 4 by setting mask
PIOA->PIO_IMR = PIO_PER_P3|PIO_PER_P4;
// set priority and enable interrupt for port A
NVIC_SetPriority(PIOA_IRQn, 3);
NVIC_EnableIRQ(PIOA_IRQn);
}
void InitializeUart(void)
{
PMC->PMC_PCER0 = ID_UART;
// baud rate is 84Mhz/(16*45)
UART->UART_BRGR = uint32_t(45);
UART->UART_CR = UART_CR_TXEN|UART_CR_RXEN;
NVIC_SetPriority(UART_IRQn,2);
NVIC_EnableIRQ(UART_IRQn);
}
void SysTick_Handler(void)
{
if (LED_status == 0)
{
PIOA->PIO_SODR = PIO_PER_P0;
LED_status = 1;
}
else
{
PIOA->PIO_CODR = PIO_PER_P0;
LED_status = 0;
}
}
void PIOA_Handler(void)
{
uint32_t PORTA_interrupt_status = 0;
PORTA_interrupt_status = PIOA->PIO_ISR;
if ((PORTA_interrupt_status&PIO_PER_P3) == 1)
{
left_tick = left_tick+1;
}
if ((PORTA_interrupt_status&PIO_PER_P4) == 1)
{
right_tick = right_tick + 1;
}
}
void UART_Handler(void)
{
}
int main(void)
{
/* Initialize the SAM system */
SystemInit();
InitializeSystemTimer();
InitializeIOPorts();
/* Replace with your application code */
while (1)
{
}
}
You should double check an example given in the Atmel SAM3X8E Datasheet in the section 31.6 I/O Lines Programming Example.
Have a look at example provided:
Four output signals on I/O lines 4 to 7 (to drive LEDs for example),
driven high and low, no pull-up resistor
and the following configuration:
Register Value to be Written
PIO_PER 0x0000FFFF
PIO_PDR 0xFFFF0000
PIO_OER 0x000000FF
PIO_ODR 0xFFFFFF00
PIO_IFER 0x00000F00
PIO_IFDR 0xFFFFF0FF
PIO_SODR 0x00000000
PIO_CODR 0x0FFFFFFF
PIO_IER 0x0F000F00
PIO_IDR 0xF0FFF0FF
PIO_MDER 0x0000000F
PIO_MDDR 0xFFFFFFF0
PIO_PUDR 0xF0F000F0
PIO_PUER 0x0F0FFF0F
PIO_ABSR 0x00F00000
PIO_OWER 0x0000000F
PIO_OWDR 0x0FFFFFF0
We need the second character from the end (as far as pins 4 to 7 are used in this example) to determine wheather the register should be programmed or not. For instance, "PIO_PER 0x0000FFFF" means the register should be programmed. And, in contrast, "PIO_PDR 0xFFFF0000" means the register should be left untouched.
Thus, the following configuration could is obtained:
PIOA->PIO_PER = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_OER = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_IFDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_CODR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_IDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_MDDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_PUDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_OWDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
I have no SAM3X8E device to check this configuration, but the above considerations may help to find a solution to your problem.

LIS3DSH x y z axis is incorrect

I have tried to work with LIS3DSH sensor using SPI protocol. I applied procedures on STM32L0 Discovery kit LoRa. But it didn't work.
My problem is The LIS3DSH x-y-z-axis output value is invalid and the value is not changed. No matter which direction I rotate the device but I check ID of LIS3DSH is correct ( 0011 1111)
Component
STM32L0 Discovery kit LoRa
LIS3DSH (https://www.amazon.com/LIS3DSH-High-Resolution-Three-axis-Accelerometer-Triaxial/dp/B07QS5D9K9/ref=sr_1_4?dchild=1&keywords=LIS3DSH&qid=1615701212&sr=8-4)
init SPI2
...
void HW_SPI2_Init(void)
{
/*##-1- Configure the SPI2 peripheral */
/* Set the SPI parameters */
hspi2.Instance = SPI2;
hspi2.Init.BaudRatePrescaler = SpiFrequency(10000000);
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0
hspi2.Init.CLKPhase = SPI_PHASE_2EDGE; // CPHA = 1
// hspi2.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
// hspi2.Init.DataSize = SPI_DATASIZE_16BIT;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCPolynomial = 10;
SPI2_CLK_ENABLE(); // Enable clock for SPI 2
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-2- Configure the SPI GPIOs */
HW_SPI2_IoInit();
}
...
initialization LIS3DSH
void HW_SPI2_IoInit(void)
{
GPIO_InitTypeDef initStruct = {0};
initStruct.Mode = GPIO_MODE_AF_PP;
initStruct.Pull = GPIO_PULLUP ;
initStruct.Speed = GPIO_SPEED_FAST;
initStruct.Alternate = SPI2_AF;
HW_GPIO_Init(LIS3DH_SCLK_PORT, LIS3DH_SCLK_PIN, &initStruct);
HW_GPIO_Init(LIS3DH_MISO_PORT, LIS3DH_MISO_PIN, &initStruct);
HW_GPIO_Init(LIS3DH_MOSI_PORT, LIS3DH_MOSI_PIN, &initStruct);
initStruct.Mode = GPIO_MODE_OUTPUT_PP;
initStruct.Pull = GPIO_NOPULL;
HW_GPIO_Init(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, &initStruct);
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 1);
}
CS ON or OFF
void HW_SPI2_CS_ON (void)
{
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 0);
}
void HW_SPI2_CS_OFF (void)
{
HW_GPIO_Write(LIS3DH_NSS_PORT, LIS3DH_NSS_PIN, 1);
}
Read ID
uint8_t LIS3DSH_DH_CHECK_ID (void)
{
uint8_t addr = LIS3Dx_WHO_AM_I_ADDR | LIS3Dx_READ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
UsingTypeint_LIS3DSH_DH.ID = au8BufferRead_SPI2[0];
return UsingTypeint_LIS3DSH_DH.ID;
}
Read X axis ( only) (Incorrect)
void LIS3DSH_DH_GET_XYZ (void)
{
uint8_t addr = LIS3Dx_OUT_X_L_ADDR | LIS3Dx_READ ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
addr = LIS3Dx_OUT_X_H_ADDR | LIS3Dx_READ ;
HW_SPI2_CS_ON();
HW_SPI2_SPI_1byte_Write_and_Read(addr);
HW_SPI2_CS_OFF();
}
HW_SPI2_1byte_Write_and_Read
bool HW_SPI2_SPI_1byte_Write_and_Read(uint8_t u8Address)
{
if(HAL_SPI_Transmit(&hspi2, (uint8_t *)&u8Address, 1, HAL_MAX_DELAY) == HAL_OK){
if(HAL_SPI_Receive(&hspi2, (uint8_t *)&au8BufferRead_SPI2[0], 1, HAL_MAX_DELAY) == HAL_OK){
return true;
}
}
return false;
}
Signal
output X L
output X H
Am not sure if you are using the state machine and register accesses of the LIS3DSH accurately.
As a reference see the register mapping in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.h (start at line 95) and the code in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.c
The function that actually writes and reads the SPI bus is void ACCELERO_IO_Write(uint8_t *pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) and void ACCELERO_IO_Read(uint8_t *pBuffer, uint8_t ReadAddr, uint16_t NumByteToRead)
This is defined in https://documentation.help/STM32F4-Discovery-BSP/stm32f4__discovery_8c_source.html at lines 560 and 594
In void ACCELERO_IO_Write(uint8_t *pBuffer, uint8_t WriteAddr, uint16_t NumByteToWrite) the actual SPI write is done at lines 574 to 582
00574 SPIx_WriteRead(WriteAddr);
00577 while(NumByteToWrite >= 0x01)
00578 {
00579 SPIx_WriteRead(*pBuffer);
00580 NumByteToWrite--;
00581 pBuffer++;
00582 }
(as always with SPI first activate register, then write data...)
In SPIx_WriteRead(WriteAddr); the WriteAddr is taken from the register mapping in https://github.com/STMicroelectronics/stm32-lis3dsh/blob/main/lis3dsh.h, start at line 9
(the above code by STM for the LIS3DSH is nice work, this implementation is very clean and structured)
The datasheet of the LIS3DSH is in https://www.st.com/resource/en/datasheet/lis3dsh.pdf, the reference manual is far more detailed it is in https://www.st.com/resource/en/application_note/dm00026768-lis3dsh-3axis-digital-output-accelerometer-stmicroelectronics.pdf it also includes explanation of the state machines, that have to be configured before the device works

Flexcan implementation in K66f microcontroller

I am trying to implement a flexcan communication using a k66f micro controller. As an initial step I just want to send a message through the tx pin. I am basing my program on an example from NXP.
I am very new to C and specially to micro controller programming. The code I run gets stuck in the following line:
/* Wait until CAN Message send out. */
while (!FLEXCAN_GetMbStatusFlags(base, 1 << mbIdx))
{
}
I don't know how exactly the meaning of the code since as I understand, FLEXCAN_GetMbStatusFlags is not a function.
Thanks in advance.
the micro controller is nxp's k66f.
Edit: This is the example
#include "fsl_debug_console.h"
#include "fsl_flexcan.h"
#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define EXAMPLE_CAN CAN0
#define EXAMPLE_CAN_CLKSRC kCLOCK_BusClk
#define EXAMPLE_FLEXCAN_IRQn CAN0_ORed_Message_buffer_IRQn
#define EXAMPLE_FLEXCAN_IRQHandler CAN0_ORed_Message_buffer_IRQHandler
#define RX_MESSAGE_BUFFER_NUM (8)
#define TX_MESSAGE_BUFFER_NUM (9)
int status;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
volatile bool rxComplete = false;
flexcan_frame_t txFrame, rxFrame;
/*******************************************************************************
* Code
******************************************************************************/
/*!
* #brief Main function
*/
int main(void)
{
flexcan_config_t flexcanConfig;
flexcan_rx_mb_config_t mbConfig;
/* Initialize board hardware. */
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("\r\n==FlexCAN loopback functional example -- Start.==\r\n\r\n");
/* Init FlexCAN module. */
/*
* flexcanConfig.clkSrc = kFLEXCAN_ClkSrcOsc;
* flexcanConfig.baudRate = 125000U;
* flexcanConfig.maxMbNum = 16;
* flexcanConfig.enableLoopBack = false;
* flexcanConfig.enableSelfWakeup = false;
* flexcanConfig.enableIndividMask = false;
* flexcanConfig.enableDoze = false;
*/
FLEXCAN_GetDefaultConfig(&flexcanConfig);
flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri;
//flexcanConfig.enableLoopBack = true;
FLEXCAN_Init(EXAMPLE_CAN, &flexcanConfig, CLOCK_GetFreq(EXAMPLE_CAN_CLKSRC));
/* Setup Rx Message Buffer. */
mbConfig.format = kFLEXCAN_FrameFormatStandard;
mbConfig.type = kFLEXCAN_FrameTypeData;
mbConfig.id = FLEXCAN_ID_STD(0x123);
FLEXCAN_SetRxMbConfig(EXAMPLE_CAN, RX_MESSAGE_BUFFER_NUM, &mbConfig, true);
/* Setup Tx Message Buffer. */
FLEXCAN_SetTxMbConfig(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, true);
/* Enable Rx Message Buffer interrupt. */
FLEXCAN_EnableMbInterrupts(EXAMPLE_CAN, 1 << RX_MESSAGE_BUFFER_NUM);
EnableIRQ(EXAMPLE_FLEXCAN_IRQn);
/* Prepare Tx Frame for sending. */
txFrame.format = kFLEXCAN_FrameFormatStandard;
txFrame.type = kFLEXCAN_FrameTypeData;
txFrame.id = FLEXCAN_ID_STD(0x123);
txFrame.length = 8;
txFrame.dataWord0 = CAN_WORD0_DATA_BYTE_0(0x11) | CAN_WORD0_DATA_BYTE_1(0x22) | CAN_WORD0_DATA_BYTE_2(0x33) |
CAN_WORD0_DATA_BYTE_3(0x44);
txFrame.dataWord1 = CAN_WORD1_DATA_BYTE_4(0x55) | CAN_WORD1_DATA_BYTE_5(0x66) | CAN_WORD1_DATA_BYTE_6(0x77) |
CAN_WORD1_DATA_BYTE_7(0x88);
/* Send data through Tx Message Buffer using polling function. */
status=FlEXCAN_TransferSendBlocking(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, &txFrame);
PRINTF("status= %d \r\n", status);
PRINTF("Send message from MB%d to MB%d\r\n", TX_MESSAGE_BUFFER_NUM, RX_MESSAGE_BUFFER_NUM);
PRINTF("tx word0 = 0x%x\r\n", txFrame.dataWord0);
PRINTF("tx word1 = 0x%x\r\n", txFrame.dataWord1);
/* Waiting for Message receive finish. */
while (!rxComplete)
{
}
PRINTF("\r\nReceved message from MB%d\r\n", RX_MESSAGE_BUFFER_NUM);
PRINTF("rx word0 = 0x%x\r\n", rxFrame.dataWord0);
PRINTF("rx word1 = 0x%x\r\n", rxFrame.dataWord1);
/* Stop FlexCAN Send & Receive. */
FLEXCAN_DisableMbInterrupts(EXAMPLE_CAN, 1 << RX_MESSAGE_BUFFER_NUM);
PRINTF("\r\n==FlexCAN loopback functional example -- Finish.==\r\n");
while (1)
{
__WFI();
}
}
void EXAMPLE_FLEXCAN_IRQHandler(void)
{
/* If new data arrived. */
if (FLEXCAN_GetMbStatusFlags(EXAMPLE_CAN, 1 << RX_MESSAGE_BUFFER_NUM))
{
FLEXCAN_ClearMbStatusFlags(EXAMPLE_CAN, 1 << RX_MESSAGE_BUFFER_NUM);
FLEXCAN_ReadRxMb(EXAMPLE_CAN, RX_MESSAGE_BUFFER_NUM, &rxFrame);
rxComplete = true;
}
}

Arduino serial works fine with Debian but hangs with Raspbian

I'm working on a personal home automation project.
On the server side, I have an Arduino Pro Mini with:
a 433 MHz TX module on pin 2
a 433 MHz RX module on pin 3
a DHT22 probe on pin 4 (with 10k pull-up)
a DHT22 probe on pin 5 (with 10k pull-up)
I have two absolutely identical of these modules; one will be the radio relay (and DHT "server") and the other a secondary DHT "server".
When it is linked to my laptop (Debian Wheezy) through an FTDI cable, it can read both local probes and switch my wall plugs on/off thanks to a C program I wrote. I'd like to use it from a Raspberry Pi. But on the Raspberry Pi (with the same FTDI cable on USB), it executes the first command I send and then hangs my terminal, forcing me to use CTRL+C.
Here is the sketch on the Arduino side (header) :
/**
* probe.h
*
* #author David Mézière <...>
*/
/**
* DHT probe result
*
*/
struct Probe {
float temperature;
float humidity;
};
Main file :
/**
* probe.ino
*
* #author David Mézière <...>
*/
#include "probe.h"
/**
* Uses DHT sensor library, from Adafruit.
* #see https://github.com/adafruit/DHT-sensor-library
*/
#include <DHT.h>
/**
* Uses RC Switch library, from sui77.
* #see https://github.com/sui77/rc-switch
*/
#include <RCSwitch.h>
// Pinout definitions
#define TX 2 // 433 MHz transmitter pin number
#define RX 3 // 433 MHz receiver pin number
#define PROBE1 4 // First DHT22 probe pin number
#define PROBE2 5 // Second DHT22 probe pin number
#define LED 13 // On-board status LED pin number
RCSwitch radio = RCSwitch();
// DHT probes definition
DHT dht1(PROBE1, DHT22);
DHT dht2(PROBE2, DHT22);
// Incomming command buffer
byte cmd[9];
/**
* Setup
*
* #return void
*/
void setup()
{
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Serial.begin(9600);
Serial.setTimeout(1000); // doesn't fix the problem
// Attach receiver to interrupt 1, meaning pin 3
radio.enableReceive(1);
radio.enableTransmit(TX);
dht1.begin();
dht2.begin();
// Debug: Internal LED will blink 3 times rapidly to show when a reboot occurs.
for (int i = 0; i < 3; i++) {
digitalWrite(LED, HIGH);
delay(250);
digitalWrite(LED, LOW);
delay(250);
}
}
/**
* Loop
*
* #return void
*/
void loop()
{
if (Serial.available() == 9 && readCommand()) {
// Lights-up internal LED to show when a command has been executed
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
}
}
/**
* Query probe
*
* Query provided [dht] probe until [retry] times for both temperature and humidity.
*
* #param DHT dht Pointer to DHT object
* #param int retry Number of tries
* #return Probe Probe result (float temperature in °C, float humidity in %)
*/
Probe queryProbe(DHT* dht, int retry)
{
Probe probe;
// Query DHT22 probe for temperature, a maximum of [retry] times.
for (int t = 0; t < retry; t++) {
probe.temperature = dht->readTemperature(false);
if (!isnan(probe.temperature)) {
break;
}
delay(50);
}
// Query DHT22 probe for humidity, a maximum of [retry] times.
for (int h = 0; h < retry; h++) {
probe.humidity = dht->readHumidity();
if (!isnan(probe.humidity)) {
break;
}
delay(50);
}
return probe;
}
/**
* Read command
*
* If serial buffer contains 2 bytes, move them to a local buffer and return true. else return false.
*
* #return boolean
*/
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// Calculates the check sum of payload
int sum = cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ cmd[7];
// Checking header and checksum a header of 0xBA 0xB1 means DHT query
if (cmd[0] == 0xBA && cmd[1] == 0xB1 && cmd[8] == sum) {
unsigned int module = cmd[2];
unsigned int probe = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
Probe result;
switch (module) {
case 1:
// Selects the right probe
if (probe == 1) {
result = queryProbe(&dht1, 3);
} else if (probe == 2) {
result = queryProbe(&dht2, 3);
}
// Send status repport to client
Serial.print("1;");
Serial.print(module);
Serial.print(";");
Serial.print(probe);
Serial.print(";");
Serial.print(result.temperature);
Serial.print(";");
Serial.println(result.humidity);
Serial.flush(); // Doesn't fix the problem
break;
}
return true;
// A header of 0xBA 0xB2 means rf wall plugs query
} else if (cmd[0] == 0xBA && cmd[1] == 0xB2 && cmd[8] == sum) {
unsigned int proto = cmd[2];
unsigned int length = cmd[3];
unsigned int value = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
radio.send(value, length);
// Send status repport to client
Serial.print("2;");
Serial.print(proto);
Serial.print(";");
Serial.print(length);
Serial.print(";");
Serial.print(value);
Serial.print(";");
Serial.println("OK");
Serial.flush(); // Doesn't fix the problem
return true;
} else {
Serial.println("KO");
Serial.flush(); // Doesn't fix the problem
return false;
}
}
And on the client side :
/**
* probe.c
*
* #author David Mézière <...>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <getopt.h>
const char* device;
static int module = 0; // uint_8 ?
static int probe = 0; // uint_8 ?
const char* proto;
static int length = 0; // uint_8 ?
static int value = 0; // uint_32 ?
static int verbose = 0; // uint_8 ?
void help()
{
printf("usage:\n");
printf("\n");
printf("probe [options] [arguments]\n");
printf("\n");
printf("options:\n");
printf(" -h|--help: Displays this help and exit\n");
printf(" -v|--verbose: Be more verbose\n");
printf("\n");
printf("arguments:\n");
printf(" -d|--device: string Serial device to use (ex: /dev/ttyUSB0)\n");
printf(" -m|--module: integer DHT22 module to query\n");
printf(" -p|--probe: integer DHT22 probe to query\n");
printf(" -r|--proto: string Radio / IR protocol\n");
printf(" -l|--length: integer Radio / IR value length in bits\n");
printf(" -a|--value: integer Radio / IR value\n");
printf("\n");
printf("examples:\n");
printf(" probe --device /dev/ttyUSB0 --module 1 --probe 1 : Will query first DHT22 probe of first module\n");
printf(" probe --proto radio1 --length 12 --value 5393 : Will send value 5393 on 12 bits over the air using protocol 1\n");
printf(" probe --proto ir11 --length 64 --value 3772793023 : Will send value 3772793023 on 64 bits by infra red using protocol 11\n");
}
void parseArgs(int argc, char **argv)
{
int c;
while (1) {
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"module", required_argument, 0, 'm'},
{"probe", required_argument, 0, 'p'},
{"proto", required_argument, 0, 'r'},
{"length", required_argument, 0, 'l'},
{"value", required_argument, 0, 'a'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, "d:hm:p:v", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) {
break;
}
switch (c) {
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) {
break;
}
printf("option %s", long_options[option_index].name);
if (optarg) {
printf (" with arg %s", optarg);
}
printf("\n");
break;
case 'd':
device = optarg;
break;
case 'h':
help();
exit(0);
break;
case 'm':
module = atoi(optarg);
break;
case 'p':
probe = atoi(optarg);
break;
case 'r':
proto = optarg;
break;
case 'l':
length = atoi(optarg);
break;
case 'a':
value = atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
putchar('\n');
}
if (&device[0] == '\0') {
fprintf(stderr, "--device is mandatory\n");
exit(1);
} else if (verbose) {
printf("Device: %s\n", device);
}
if (verbose) {
printf("Querying probe %i of module %i.\n", probe, module);
}
}
void initSerial(int fd)
{
struct termios toptions;
/* get current serial port settings */
tcgetattr(fd, &toptions);
/* set 9600 baud both ways */
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);
/* 8 bits, no parity, no stop bits */
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
/* Canonical mode */
toptions.c_lflag |= ICANON;
/* commit the serial port settings */
tcsetattr(fd, TCSANOW, &toptions);
}
int main(int argc, char **argv)
{
// Parses command line arguments
parseArgs(argc, argv);
int fd, n, i;
char buf[64] = "temp text";
/* open serial port */
fd = open(device, O_RDWR | O_NOCTTY);
if (verbose) {
printf("Device %s opened as %i\n", device, fd);
}
/*
* Note: Most Arduinos models will reboot upon connection, and they need
* some time for it. I use a pro/mini that doesn't, so i commented it out.
*/
// usleep(3500000);
// Sets the serial port settings (9600 bps, 8 bits, no parity, no stop bits)
initSerial(fd);
/**
* 72 bits
* | Header | Param 1 | Param 2 | Param 3 | sum |
* | 16 b | 8 b | 8 b | 32 b | 8 b |
* Cas 1 : Requête DHT | 0xba 0xb1 | module | 0x00 | sonde | sum |
* Cas 2 : Requête radio | 0xba 0xb2 | proto | length | value | sum |
* Cas 3 : Requête IR | 0xba 0xb3 | proto | length | value | sum |
*/
unsigned char oBuf[9];
// printf("%s\n", proto);
// printf("%i\n", length);
if (module > 0 && probe > 0) {
if (verbose) {
printf("DHT mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB1; // DHT query
oBuf[2] = module;
oBuf[3] = 0x00;
oBuf[4] = (probe >> 24) & 0xFF;
oBuf[5] = (probe >> 16) & 0xFF;
oBuf[6] = (probe >> 8) & 0xFF;
oBuf[7] = probe & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
// sprintf(oBuff, "%c%c%c%c%c%c", 0xba, 0xb1, module, 0x00, probe, sum);
} else if (strcmp((const char*)proto, "radio1") == 0 && length > 0) {
if (verbose) {
printf("Radio mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB2; // Radio query
oBuf[2] = 0x01; // Protocol 1
oBuf[3] = length;
oBuf[4] = (value >> 24) & 0xFF;
oBuf[5] = (value >> 16) & 0xFF;
oBuf[6] = (value >> 8) & 0xFF;
oBuf[7] = value & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
} else {
if (verbose) {
printf("Unknown mode\n");
}
}
/* Send the buffer */
write(fd, oBuf, 9);
/* Receive string from Arduino */
n = read(fd, buf, 64);
/* insert terminating zero in the string */
buf[n] = 0;
if (verbose) {
printf("%i bytes read, buffer contains: %s\n", n, buf);
} else {
printf("%s", buf);
}
return 0;
}
I compile it using just gcc probe.c -o probe.
On Debian, I can use the system as much as I want, it works:
dmeziere#portable2-wlan:~/dev/probe$ gcc probe.c -o probe
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.60;43.10
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
1;1;2;23.60;38.50
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5396
2;1;24;5396;OK
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5393
2;1;24;5393;OK
On Raspbian, the first call works, but the second hangs my terminal and I have to do CTRL+C:
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.90;39.00
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
^C
I found it !
It seems like on Raspbian, the communications were terminated by a NULL character. But not on Debian. And this NULL character was polluting my calculations of incomming buffer length. So i ended up by eventually suppress it on the Arduino side :
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// If sender sends a null character, remove it.
int test = Serial.peek();
if (test == 0x00) {
test = Serial.read();
}
// ...
}

Resources