Why am I getting Segmentation fault. Raspberry pi 4 C Programming - c

#include <linux/module.h>
#include <linux/kernel.h>
//#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
//#include <linux/input-polldev.h>
//#include <linux/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
/*
MAHIR SHAHRIAR
30027575
CPSC 359
ASSIGNMENT 2
*/
#define GPIO_CLOCKPIN 23 // pin used for clock output GPIO 11 (SPI_SCLK)
#define GPIO_LATCHPIN 21 // pin used for latch output GPIO 9 (SPI_MISO)
#define GPIO_DATAPIN 19 // pin used for data input from controller GPIO 10 (SPI_MOSI)
#define GPIO_POWERPIN 1 // 3.3 VOLT POWER SOURCE Programmble input to set high/low
#define GPIO_GROUNDPIN 9 // Pin used for grounding
#define GPIO_BASEADDRESS 0xfe200000 // Base address used to offset to other registers
//volatile unsigned *gpio = (unsigned*)0xfe200000; // gpio pointer to base address
volatile uint32_t *gpio = (unsigned*)0xfe200000;
volatile uint32_t *GPFSEL1 = (unsigned*)0xfe200000 + 0x04/4; //pointer to register GPFSEL1 for pins 10-19
volatile unsigned *GPFSEL2 = (unsigned*)0xfe200000 + 0x08/4; //pointer to register GPFSEL2 for pins 20-29
volatile unsigned *GPSET0 = (unsigned*)0xfe200000 + 0x1c/4; //pointer to register GPSET0 for setting high
volatile unsigned *GPCLR0 = (unsigned*)0xfe200000 + 0x28/4; //pointer to register GPCLR0 for setting low
volatile unsigned *GPLEV0 = (unsigned*)0xfe200000 + 0x34/4; //pointer to register GPLEV0 for reading data from pin
volatile unsigned *GPIO_PUP_PDN_CNTRL_REG1 = (unsigned*)0xfe200000 + 0xe8/4; //pointer to register for controlling pull up pull down
// INIT GPIO Function takes user inputs for Initializing a particular GPIO Pin number.
// It takes data such as the PIN NUMBBER , string "input" or "output" ,
// string "high" or "low " and string "pullup" or "pulldown"
// Depending on the arguments passed into the Init_GPIO function or subroutine
static void Init_GPIO(int pin_number, char type, char high_low, char pullup_pulldown) {
// setting valueinput valueoutput and mask to set the input output of the pin type
int valueinput = 0b000 << ( (pin_number-10)*3 ); // bits to be set for input
int valueoutput = 0b001 << ( (pin_number-10)*3 ); // bits to be set for output
int mask = 0b111 << ( (pin_number-10)*3 ); // for ensuring other bits dont change
// condition to check which register to access for the bits and setting to input or output based on
// function calls from main and arguments passed
if(pin_number<=19){
if(type == 'i'){
printf("%x", GPFSEL1);
//*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueinput * mask); //problem
}
else if(type == 'o'){
//*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueoutput * mask);
}
else{
//no type specified
printf("Input type not specified please use 'o' or 'i' ignore if not specifying output input type for pin\n");
}
if(pin_number > 19 && pin_number <=29 ){
if(type == 'i'){
//*GPFSEL2 = (*GPFSEL2 & ~mask) | (valueinput * mask);
}
else if(type == 'o'){
//*GPFSEL2 = (*GPFSEL2 & ~mask) | (valueoutput * mask);
}
else{
//no type specified
printf("Input type not specified please use 'o' or 'i' ignore if not specifying output input type for pin\n");
}
}
// Setting the pin to either high or low
if(high_low == 'h'){
//*GPSET0 = 1 << pin_number;
}
else if(high_low == 'l'){
//*GPCLR0 = 1 << pin_number;
}
else{
// high low not specified
printf("high low not specified please use 'h' or 'l' ignore if not specifying highlow for pin\n");
}
}
// Setting if the pin uses pull up or pull down register
int value_pullup = 0b01 << ( (pin_number -16)*2 );
int value_pulldown = 0b10 << ( (pin_number -16)*2 );
mask = 0b11 << ( (pin_number -16)*2 );
if(pullup_pulldown == 'p'){
//*GPIO_PUP_PDN_CNTRL_REG1 = ( *GPIO_PUP_PDN_CNTRL_REG1 & ~mask ) | (value_pullup) & mask;
}
else if(pullup_pulldown == 'n'){
//*GPIO_PUP_PDN_CNTRL_REG1 = ( *GPIO_PUP_PDN_CNTRL_REG1 & ~mask ) | (value_pulldown) & mask;
}
else {
// user does not set any pull up or pull down value for the assigned pin
printf("pull up pull down not specified please use 'p' or 'n' ignore if not specifying pullup pulldown for pin\n");
}
}
void main() {
printf("pointer address %p " , gpio);
Init_GPIO(18, 'i', 'l', 'p');
volatile uint32_t valueinput = 0b000 << ( (18-10)*3 ); // bits to be set for input
volatile uint32_t valueoutput = 0b001 << ( (18-10)*3 ); // bits to be set for output
volatile uint32_t mask = 0b111 << ( (18-10)*3 );
*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueinput * mask);
}
I am getting segmentation error for the last line in main. I dont know why this is doing that. How do I fix the issue I am trying to change the bits in the register GPFSEL1 for the raspberry pi 4 GPIO for changing the input mode by changing bits to 000 for my pin 18 for putting in into input mode. Any help or direction would be greatly appreciated!

Related

synthesizer - recording pressed keypad

I have to build synthesizer and I am using C for programing my ATmega128A. I need to record the keypads pressed and play them after some time. For keypad press I am using polling in the main.c. For playing the keypads I am using Timer1. Every time when the timer expires I am storing the keypad frequency and increment counter for it. During play, I calculate the duration firstle, then play it for that interval. When I want to play the stored song, it ticks for some time and starts to make a long sound.
Also, I want to make possible to press, record and palay simultanous keypads. Can you suggest some algorithm for this?
main.c
#include <avr/io.h>
#include <avr/interrupt.h>
#include "keypad.h"
unsigned char temp; // to get keyboard input to play a note
unsigned char option; //to choose the embedded music to play
#define DELAY 1000
int main(void)
{
DDRG = 0xff; // To send sound to BUZ speakers (BUZ is connected to PG.4)
DDRD = 0x00; // Make it input, to get corresponding key to play a note
PORTD = 0xff; // All bits are 1s, so no button is pressed in the beginning
sei(); //Set Interrupt flag as enabled in SREG register
option = no_music; //No music is played on startup, this is default mode for free playing
// This loop keeps playing forever, so the main functionality
// of the program is below
DDRB = 0xff;
DDRD = 0x00; //ready for input
while(1)
{
temp = PIND; //store keyboard input for temporary variable
//PORTB = PIND;
switch(temp)
{
case 254: { // if 1st pin of PORTD is pressed
play_note(notes5[0]); // play corresponding note from octave 5 for 200ms
break;
}
case 253: { // if 2nd pin of PORTD is pressed
play_note(notes5[1]);
break;
}
case 251: { // if 3rd pin of PORTD is pressed
play_note(notes5[2]);
break;
}
case 247: { // if 4th pin of PORTD is pressed
play_note(notes5[3]);
break;
}
case 239: { // if 5th pin of PORTD is pressed
play_note(notes5[4]);
break;
}
case 223: { // if 6th pin of PORTD is pressed
play_note(notes5[5]);
break;
}
case 191: { // if 7th pin of PORTD is pressed
play_note(notes5[6]);
break;
}
case 127: {
if(isRecordingEnabled){
disableRecording();
//toggling LED as the sign of playing the record
toggleLED();
custom_delay_ms(DELAY);
toggleLED();
custom_delay_ms(DELAY);
custom_delay_ms(DELAY);
play_record();
}else{
//toggling LED as the sign of record start
toggleLED();
enableRecording();
}
}
}
}
return 0;
}
keypad.c
#include "structs.h"
#include "play.h"
#define F_CPU 16000000UL // 16 MHz
#include <util/delay.h>
#define BUFFER_SIZE 100
struct played_note buffer[BUFFER_SIZE];
int i = 0;
int8_t isRecordingEnabled = 0;
int8_t recordIndex = 0;
int8_t pressedNote;
int8_t isPressed = 0;
int8_t isPlaying = 0;
unsigned int ms_count = 0;
#define INTERVAL 100
#define DELAY_VALUE 0xFF
ISR(TIMER1_COMPA_vect){
// every time when timer0 reaches corresponding frequency,
// invert the output signal for BUZ, so it creates reflection, which leads to sound generation
//check whether the key was pressed because
//when the recording is enabled the interrupt is working make sound
if(isPressed || isPlaying)
PORTG = ~(PORTG);
if(isRecordingEnabled){
if(PIND == DELAY_VALUE)
pressedNote = DELAY_VALUE;
if(i == 0){
buffer[i].note = pressedNote;
buffer[i].counter = 0;
i++;
}else{
if(buffer[i - 1].note == pressedNote){
//the same note is being pressed
buffer[i - 1].counter++;
}else{
buffer[i++].note = pressedNote;
buffer[i].counter = 0;
}
}
}
}
void initTimer1(){
TIMSK = (1 << OCIE1A); //Timer1 Comparator Interrupt is enabled
TCCR1B |= (1 << WGM12) | (1 << CS12); //CTC mode, prescale = 256
}
void stopTimer1(){
TIMSK &= ~(1UL << OCIE1A);
TCCR1A = 0; //stop the timer1
TIFR = (1 << OCF1A); //Clear the timer1 Comparator Match flag
}
void enableRecording(){
isRecordingEnabled = 1;
i = 0;
ms_count = 0;
initTimer1();
}
void disableRecording(){
isRecordingEnabled = 0;
stopTimer1();
}
//Timer1A
void play_note_during(unsigned int note, unsigned int duration){
OCR1A = note;
pressedNote = note;
isPressed = 1;
initTimer1();
custom_delay_ms(duration);
stopTimer1();
isPressed = 0;
}
//Timer1A
void play_note(unsigned int note){
play_note_during(note, INTERVAL);
}
void play_record(){
isPlaying = 1;
recordIndex = 0;
int duration;
while(recordIndex < i){
PORTB = buffer[return].counter << 8;
duration = INTERVAL * buffer[recordIndex].counter;
if(buffer[recordIndex].note == DELAY_VALUE)
custom_delay_ms(duration);
else
play_note_during(buffer[recordIndex].note, duration);
recordIndex++;
}
isPlaying = 0;
}
Further references can be found in the following github repository:
https://github.com/bedilbek/music_simulation
Actually your question about how to record and replay key presses, should be anticipated by another question about how to play several sounds simultaneously.
Now you're using just PWM output with variable frequency. But this allows you to generate only a single wave of a square form. You cannot play two notes (except of using another timer and another PWM output).
Instead of that, I suggest you to use PWM at the highest frequency and apply a RC or LC filters to smooth high-frequency PWM signal into a waveform, and then apply that waveform to the amplifier and to the speaker to make a sound.
Having this approach you make generate different waveforms, mix them together, make them louder or more silent and even apply a "fade-out" effect to make them sound like a piano.
But your question is not about how to generate that kind of wave-forms, so if you want to know you should start another question.
So, returning to your question.
Instead of having single procedure, which is starting note, holding a pause and only then returning back; I suggest you to have a several procedures, one play_note(note) - which will start playing a note and returns immediately (while note continue playing). And, of course, stop_note(note) - which will stop specified note, if it is played. Also I suggest you to pass a note number, rather than frequency or timer period to the play function. Let's assume 0 is the lowest possible note (e.g. C2), and then they go sequentially by semitones: 1 - C#2, 2 - D2, .... 11 - B2, 12 - C3 ... etc.
For the first time, you may remake your single-note playing procedures to match that.
// #include <avr/pgmspace.h> to store tables in the flash memory
PROGMEM uint16_t const note_ocr_table[] = {
OCR1A_VALUE_FOR_C2, OCR1A_VALUE_FOR_C2_SHARP, ... etc
}; // a table to map note number into OCR1A value
#define NOTE_NONE 0xFF
static uint8_t current_note = NOTE_NONE;
void play_note(uint8_t note) {
if (note >= (sizeof(note_ocr_table) / sizeof(note_ocr_table[0])) return; // do nothing on the wrong parameter;
uint16_t ocr1a_val = pgm_read_word(&note_ocr_table[note]);
TIMSK = (1 << OCIE1A); //Timer1 Comparator Interrupt is enabled // why you need this? May be you want to use just inverting OC1A output?
TCCR1B |= (1 << WGM12) | (1 << CS12); //CTC mode, prescale = 256 // you may want to use lesser prescalers and higher OCR1A values ?
OCR1A = ocr1a_val;
if (TCNT1 >= ocr1a_val) TCNT1 = 0; // do not miss the compare match when ORC1A is changed to lower values;
current_note = note;
}
void stop_note(uint8_t note) {
if (note == current_note) { // ignore stop for non-current note.
TIMSK &= ~(1UL << OCIE1A);
TCCR1A = 0; //stop the timer1
TIFR = (1 << OCF1A); //Clear the timer1 Comparator Match flag
current_note = NOTE_NONE; // No note is playing
}
}
so, now your task is very simple: you should just pull the state of the keys periodically, let's say 61 times per second (based on the some 8-bit timer with 1:1024 prescaler overflow), and they to note: which keys are changed their state. If some key is pressed, you call play_note to start coressponding note. If the key is released, you call stop_note, also you're counting how many timer cycles passed since the last event.
When recording, you just push those events into array "key X is pressed" or "key X is released" or "X timer cycles expired".
When playing back, you just performing a backward process, scaning your array, and executing commands: calling play_note, stop_note, or waiting exact amount of timer cycles, if it is a pause.
Instead of writing giant switch statement, you may also use a table to scan the buttons
// number of element in the port-state arrays
#define A 0
#define B 1
#define C 2
#define D 3
#define E 4
#define F 5
typedef struct {
port_index uint8_t;
mask uint8_t;
} KeyLocation;
PROGMEM KeyLocation const key_location[] = {
{ B, (1 << 1) }, // where C2 is located, e.g. PB1
{ E, (1 << 3) }, // where C#2 is located, e.g. PE3
...
}
uint16_t ticks_from_prev_event = 0;
uint8_t port_state_prev[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0XFF};
for (;;) { // main loop
wait_tick_timer_to_overflow();
// latching state of the pins
uint8_t port_state[6] = {PINA, PINB, PINC, PIND, PINE, PINF};
for (uint8_t i = 0 ; i < (sizeof(key_location) / sizeof(key_location[0])) ; i++) {
uint8_t port_idx = pgm_read_byte(&key_location[i].port_index);
uint8_t mask = pgm_read_byte(&key_location[i].mask);
if ((port_state[port_idx] & mask) != (port_state_prev[port_idx] & mask)) { // if pin state was changed
if (is_recording && (ticks_from_prev_event > 0)) {
put_into_record_pause(ticks_from_prev_event); // implement it on your own
}
if ((port_state[port_idx] & mask) == 0) { // key is pressed
play_note(i);
if (is_recording) {
put_into_record_play_note(i); // implement
}
} else { // key is released
stop_note(i);
if (is_recording) {
put_into_record_stop_note(i); // implement
}
}
}
}
// the current state of the pins now becomes a previous
for (uint8_t i = 0 ; i < (sizeof(port_state) / sizeof(port_state[0])) ; i++) {
port_state_prev[i] = port_state[i];
}
if (ticks_from_prev_event < 65535) ticks_from_prev_event++;
}
put_into_record_... implement as you wish.
the playback would be the same simple (below just the template, you'll suggest from the function name what they should do)
while (has_more_data_in_the_recording()) {
if (next_is_play()) {
play_note(get_note_from_recording())
} else if (next_is_stop()) {
play_note(get_note_from_recording())
} else {
uint16_t pause = get_pause_value_from_recording();
while (pause > 0) {
pause--;
wait_tick_timer_to_overflow();
}
}
}
This approach gives you two benefits:
1) It doesn't matter how many notes the playing module can play, the keys are recorder while they are pressed and released, so, all simultaneous keys will be recorded and replayed in the same time.
2) It doesn't matter how many notes are pressed in exact the same moment. Since pause and key events are recorded separately, during the replay all the same-time key presses will be replayed in the same time, without an "arpeggio" effect

errors encountered while interfacing eeprom with microcontroller

I am not an expert c programmers and in the c code I m getting these kinds of errors. I got many and tried to sort them out but can not solve these. The code is as follows:
/*
* EEPROM.c
* interfacing microchip 24aa64f IC with atmel sam4e
*/
#include <asf.h>
#include "EEPROM_I2C.h"
#define DEVICE_ADDRESS 0x50 // 7-bit device identifier 0101000, (refer datasheet)
//#define EEPROM_NAME 24AA6F
#define I2C_FAST_MODE_SPEED 400000//TWI_BUS_CLOCK 400KHz
#define TWI_CLK_DIVIDER 2
#define TWI_CLK_DIV_MIN 7
#define TWI_CLK_CALC_ARGU 4
#define TWI_CLK_DIV_MAX 0xFF
/*************************** Main function ******************************/
int eeprom_main( void )
{
struct micro24 ptMicro24 ;
typedef struct twi_options twi_options_t;
typedef struct Twi_registers Twi;
char TxBuffer[128] ;
char RxBuffer[128] ;
int BufferIndex;
unsigned int PageCount;
unsigned int error = 0 ;
unsigned int i;
ptMicro24.PageSize = 32;
ptMicro24.NumOfPage = 128;
ptMicro24.EepromSize = 128*32;
ptMicro24.SlaveAddress = DEVICE_ADDRESS;
ptMicro24.EepromName = 64;
/***************************** CLOCK SETTINGS TO GET 400KHz **********************
* Set the I2C bus speed in conjunction with the clock frequency.
* param p_twi Pointer to a TWI instance.
* return value PASS\Fail New speed setting is accepted\rejected
**********************************************************************************/
uint32_t twi_set_speed(struct Twi_registers *Twi, uint32_t ul_speed, uint32_t ul_mck)
//uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
{
uint32_t ckdiv = 0; //clock divider is used to increase both TWCK high and low periods (16-18)
uint32_t c_lh_div; //CHDIV (0-7) and CLDIV (8-15)
if (ul_speed > I2C_FAST_MODE_SPEED) { //ul_speed is the desired I2C bus speed
return FAIL;
}
c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU; //ul_mck main clock of the device
/* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */
while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN))
{
ckdiv++; // Increase clock divider
c_lh_div /= TWI_CLK_DIVIDER; //Divide cldiv value
}
/* set clock waveform generator register */
Twi->TWI_CWGR =
TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
TWI_CWGR_CKDIV(ckdiv);
return PASS;
}
/************************************ Initialize TWI master mode ************************
* Set the control register TWI_CR by MSEN and SVDIS
* param p_opt Options for initializing the TWI module
* return TWI_SUCCESS if initialization is complete
* twi_options... structure contains clock speed, master clock, chip and smbus
*****************************************************************************************/
uint32_t twi_master_start(struct Twi_registers *Twi, struct twi_options_t *twi_options_t)
//uint32_t twi_master_start(Twi *p_twi, const twi_options_t *p_opt)
{
uint32_t status = TWI_SUCCESS; // status success return code is 0
// Enable master mode and disable slave mode in TWI_CR
Twi -> TWI_CR_START = TWI_CR_START;
Twi->TWI_CR_MSEN = TWI_CR_MSEN; // Set Master Enable bit
Twi->TWI_CR_SVDIS = TWI_CR_SVDIS; // Set Slave Disable bit
/* Select the speed */
//new//if (twi_set_speed(Twi->TWI_SR, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//if (twi_set_speed(Twi, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//{
//status = TWI_INVALID_ARGUMENT; /* The desired speed setting is rejected */
//}
if (twi_options_t->smbus == 0)
{
Twi->TWI_CR_QUICK == 0;
status = TWI_INVALID_ARGUMENT;
}
else
if (twi_options_t->smbus == 1)
{
Twi->TWI_CR_QUICK == 1;
status = TWI_SUCCESS;
}
return status;
}
/***************************** WriteByte Function ********************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
***********************************************************************************/
void WriteByte (struct micro24 *ptMicro24, char Data2Write,
unsigned int Address)
//Data2Write is the data to be written n the eeprom
//struct <micro24 *ptMicro24> : Structure of Microchip 24AA Two-wire Eeprom
//unsigned int Address>: Address where to write
{
unsigned int WordAddress;
unsigned int SlaveAddress;
unsigned char p0=0;
TWI_CR_START ==1;
if (ptMicro24->EepromName == 64 )
{
if ( Address > 0xFFFF)
{
p0 = 1;
/* Mask the 17th bit to get the 16th LSB */
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
TWI_CR_STOP ==1;
//TWI_WriteSingleIadr(TWI_IADR_IADR,SlaveAddress, WordAddress,
// TWI_MMR_IADRSZ_2_BYTE, &Data2Write); // declared as extern
// to write to internal address, utilizing internal address and master mode register
//}
/******************** Increase Speed Function *****************************
* TWI is accessed without calling TWI functions
/***************************************************************************/
int NumOfBytes, Count;
int status;
uint32_t Buffer;
/* Enable Master Mode of the TWI */
TWI_CR_MSEN == 1;
// Twi.TWI_CR_MSEN ==1;
//TWI_CR->TWI_CR_MSEN = TWI_CR_MSEN ;
/* Set the TWI Master Mode Register */
Twi->TWI_MMR = (SlaveAddress & (~TWI_MMR_MREAD) | (TWI_MMR_IADRSZ_2_BYTE));
/* Set the internal address to access the wanted page */
Twi -> TWI_IADR = WordAddress ;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
/* Send the buffer to the page */
for (Count=0; Count < NumOfBytes ;Count++ )
{
Twi ->TWI_THR_TXDATA = Buffer++;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
}
/* Wait for the Transmit complete is set */
status = TWI_SR_TXCOMP;
while (!(status & TWI_SR_TXCOMP))
status = TWI_SR_TXCOMP;
// add some wait function according to datasheet before sending the next data
// e.g: 10ms
// e.g: WaitMiliSecond (10);
}
/****************************** ReadByte Function **************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
****************************************************************************/
char ReadByte (struct micro24 *ptMicro24,
unsigned int Address) //int Address to read
{
unsigned int WordAddress;
unsigned int SlaveAddress;
char Data2Read ;
unsigned char p0=0;
TWI_CR_START == 1;
//p_twi -> TWI_CR_START = TWI_CR_START;
if (ptMicro24->EepromName == 64)
{
if ( Address > 0xFFFF) {
p0 = 1;
// Mask the 17th bit to get the 16th LSB
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
//TWI_ReadSingleIadr(TWI_IADR_IADR,SlaveAddress,WordAddress,
// TWI_MMR_IADRSZ_2_BYTE,&Data2Read);
// declared as extern
// to write to internal address, utilizing internal address and master mode register
return (Data2Read);
}
}
errors are:
(24,19): error: storage size of 'ptMicro24' isn't known
67,5): error: dereferencing pointer to incomplete type
Twi->TWI_CWGR =
error: expected identifier before '(' token
#define TWI_CR_START (0x1u << 0) /**< \brief (TWI_CR) Send a START Condition */
error: expected identifier before '(' token
#define TWI_CR_MSEN (0x1u << 2) /**< \brief (TWI_CR) TWI Master Mode Enabled */
error: expected identifier before '(' token
#define TWI_CR_SVDIS (0x1u << 5) /**< \brief (TWI_CR) TWI Slave Mode Disabled */
error: dereferencing pointer to incomplete type
if (twi_options_t->smbus == 0)
It seems missing the declaration of struct micro24, this may be the cause of first error: error: storage size of 'ptMicro24' isn't known.
The same for declaration of Twi_registers, that is causing other errors.
Either you forgot to declare these structs or to include an header file declaring them.

Data request is only returning address value (I2C) [duplicate]

This question already has answers here:
Why am I only receiving the first address byte? (I2C Protocol)
(4 answers)
Closed 6 years ago.
I'm trying to read some values being returned by a sensor device. It is all hooked up fine, but I'm struggling to retrieve data from the sensor, properly.
In the datasheet it says that I should receive bytes in the order: prediction, status, resistance, tvoc.
My terminal keeps spitting out the same value, 23130 (0x5a5a)
This leads me to believe that I'm not properly calling my i2c_start(). In the protocol readme it says to read with I2C_start(SLAVE_READ_ADDRESS);' I tried replacing the address with the so-called read starting point being 0xB5, but that returns my error.
/* Name: main.c
* Author: <insert your name here>
* Copyright: <insert your copyright message here>
* License: <insert your license reference here>
*/
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <uart.h>
#include <i2c_master.h>
#define LED PB5
#define I2C_READ 0x5A
char buffer[10];
uint16_t val = 0;
uint16_t pred = 0;
uint8_t status = 0;
uint8_t resistance = 0;
uint8_t tvoc = 0;
void getVal()
{
if(i2c_start(I2C_READ))
{
//uart_puts("Start ");
val = ((uint8_t)i2c_read_ack())<<8;
val |= i2c_read_ack();
pred = ((uint16_t)i2c_read_ack())<<8;
pred |= i2c_read_ack();
// status = ((uint8_t)i2c_read_ack())<<8;
// status |= i2c_read_ack();
// resistance = ((uint8_t)i2c_read_ack())<<8;
// resistance |= i2c_read_ack();
// tvoc = ((uint8_t)i2c_read_ack())<<8;
// tvoc |= i2c_read_nack();
i2c_stop();
} else
{
uart_puts("Error");
i2c_stop();
}
}
int main(void)
{
init_uart(57600);
i2c_init();
DDRB = _BV(5);
for(;;)
{
getVal();
itoa(val, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(pred, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(status, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(resistance, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(tvoc, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
PORTB = 0xFF;
_delay_ms(500);
PORTB = 0x00;
_delay_ms(500);
}
return 0; /* never reached */
}
The datasheet is very unclear and contains a fault as far as addressing is concerned. The address for WRITING is 0xB4 and the address for READING is 0xB5.
The datasheet says the address is:
BIT 7 6 5 4 3 2 1 0
DATA 1 0 1 1 0 1 0 R/W
which corresponds to 0xB4 or 0xB5 depending on the R/W bit beeing set or not. The error they make in the text is that (0)1011010 is 0x5A but the R/W bit is the least significant bit, not the most significant bit.
The i2c_start function in the i2cmaster library returns 1 to indicate an error, not zero
uint8_t i2c_start(uint8_t address)
{
// ... snip ...
// check if the device has acknowledged the READ / WRITE mode
uint8_t twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
return 0;
}
So in your getVal function, you should have
void getVal()
{
if(i2c_start(I2C_READ) == 0) // 0 indicates success
{
In addition, I can't see why you're reading two 16-bit values val and pred from the sensor. The datasheet indicates that pred is the first value returned. You should also read the 8-bit status value to check if the data read is valid.

I am struggling to understand this code [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I spent more time and struggling to understand this code.
I edited and manage to display the data on LCD but
I would like to understand it.
I have added some comment to the code to show my bit understanding.
// Control 16 character LCD (2x8 chars) with 4 bit interface
// Copyright (C) 2012 Joonas Pihlajamaa. Released to public domain.
// No warranties, use at your own responsibility.
#include <avr/io.h>
#define F_CPU 12000000UL // 12 MHz
#include <util/delay.h>
#define DATA_PORT_DIR DDRB // macro for data port direction
#define DATA_PORT PORTB //macro for data port
#define DATA_PORT_IN PINB //macro for data port pin
#define RW_PIN (1<<PD4) // PORTD Pin4 is defined as for RW
#define RS_PIN (1<<PD5) // PORTD Pin5 is defined as for RS
#define EN_PIN (1<<PD6) // PORTD Pin6 is defined as for EN
// macro or something else? confused?
#define SET_CTRL_BIT(pin) (PORTD |= pin)
#define CLEAR_CTRL_BIT(pin) (PORTD &= ~pin)
// assumes EN_PIN is LOW in the beginning
void lcd_write(char rs, unsigned char data)
{
if(DATA_PORT_DIR != 0xFF) // condition to test if DATA_PORT_DIR is true
//make DATA_PORT_DIR as output to write data to ldc
DATA_PORT_DIR = 0xFF;
CLEAR_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
DATA_PORT = data;
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
CLEAR_CTRL_BIT(EN_PIN);
}
unsigned char lcd_read(char rs)
{
unsigned char data;
if(DATA_PORT_DIR != 0)
DATA_PORT_DIR = 0;
SET_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
data = DATA_PORT_IN;
CLEAR_CTRL_BIT(EN_PIN);
return data;
}
void lcd_wait()
{
while(lcd_read(0) & 0x80); // wait until display is ready
}
void lcd_init()
{
_delay_ms(50); // wait for VDD to rise
lcd_write(0, 0x30);
_delay_ms(5);
lcd_write(0, 0x30);
_delay_ms(1); // _delay_us(120);
lcd_write(0, 0x30);
_delay_ms(1); // _delay_us(120);
lcd_write(0, 0x38); // 2 lines, normal font
_delay_ms(1);
lcd_write(0, 0xC); // display on
_delay_ms(1);
lcd_write(0, 1); // display clear
_delay_ms(1);
lcd_write(0, 0x6); // increment, don't shift
_delay_ms(1);
}
void lcd_puts(char * string)
{
char i;
lcd_write(0, 0x80); // move to 1st line
lcd_wait();
for(i=0; i<8; i++)
{
if(string[i] == '\0')
return;
lcd_write(1, string[i]);
lcd_wait();
}
lcd_write(0, 0x80+0x40); // move to 2nd line
lcd_wait();
for(i=8; i<16; i++)
{
if(string[i] == '\0')
return;
lcd_write(1, string[i]);
lcd_wait();
}
}
int main(void)
{
unsigned char i = 0;
char message[] = "nn Mississippi..";
DDRD = RS_PIN + EN_PIN + RW_PIN + LED_PIN; // Control outputs
DDRB = 0xFF; // Port B as DB0..DB7
lcd_init();
lcd_puts("Hello, World!!!");
_delay_ms(2000);
while(1)
{
if(++i >= 100)
i = 1;
if(i >= 10)
message[0] = i/10+'0';
else
message[0] = ' ';
message[1] = i%10+'0';
lcd_puts(message);
_delay_ms(1000);
}
return 1;
}
These define constants that have only the bit specified on
#define RW_PIN (1<<PD4) // PORTD Pin4 is defined as for RW
#define RS_PIN (1<<PD5) // PORTD Pin5 is defined as for RS
#define EN_PIN (1<<PD6) // PORTD Pin6 is defined as for EN
These Macros can then use the above can be used to set the bit (by OR'ing it on) or clearing the bit by using AND with the 1's complement of the constant (all bits on but one).
// macro or something else? confused?
#define SET_CTRL_BIT(pin) (PORTD |= pin)
#define CLEAR_CTRL_BIT(pin) (PORTD &= ~pin)
Here is what it looks that the write is doing: If first puts all the port bits in output mode (so it can write the data). It then sets RW pin low (I assume to put it in write mode) and resets the display (if rs is set) by toggling the RS bit. It then loads the data into the DATA_PORT and toggles the EN pin (I assume to load it).
// assumes EN_PIN is LOW in the beginning
void lcd_write(char rs, unsigned char data)
{
if(DATA_PORT_DIR != 0xFF) // condition to test if DATA_PORT_DIR is true
//make DATA_PORT_DIR as output to write data to ldc
DATA_PORT_DIR = 0xFF;
CLEAR_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
DATA_PORT = data;
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
CLEAR_CTRL_BIT(EN_PIN);
}
Here is what it looks that the read is doing: If first puts all the port bits in input mode (so it can read the data). It then sets RW pin high (I assume to put it in read mode) and resets the display (if rs is set) by toggling the RS bit. It then sets the EN bit and fetches the data from the DATA_PORT and turns the EN pin off again.
unsigned char lcd_read(char rs)
{
unsigned char data;
if(DATA_PORT_DIR != 0)
DATA_PORT_DIR = 0;
SET_CTRL_BIT(RW_PIN);
if(rs)
SET_CTRL_BIT(RS_PIN);
else
CLEAR_CTRL_BIT(RS_PIN);
_delay_us(2);
SET_CTRL_BIT(EN_PIN);
_delay_us(2);
data = DATA_PORT_IN;
CLEAR_CTRL_BIT(EN_PIN);
return data;
}
Is that enough for you to figure out what the rest is doing?

GPIO interrupt for different pins in PSoC 1

I have faced a problem connected with GPIO interrupt.
The task is to make a simple UI interface, so I need to use 3 buttons.
The problem is that I don't understand how to use GPIO interrupt for different pins and all my buttons work the same way.
here is the code:
#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int value; // the actual value which is used in the module
char string[16]; // string that is printed in LCD for user
} UI_ELEMENT;
#define FIRST_LEVEL 3
#define SECOND_LEVEL 3
#define PWM 0
#define PGA 1
#define ADC 2
#define PWM_STATE 0
#define PWM_PERIOD 1
#define PWM_WIDTH 2
#define PWM_STATE_OFF 0
#define PWM_STATE_ON 1
volatile int buttonRightPressed = 0;
#pragma interrupt_handler buttonRightInt
void buttonRightInt(void){
// disable button interrupt
M8C_DisableIntMask(INT_MSK0, INT_MSK0_GPIO);
buttonRightPressed = 1;
}
void initialize_LCD(void){
LCD_Position(0,0);
LCD_PrCString("PWM");
LCD_Position(1,0);
LCD_PrCString("< select >");
}
void update_LCD(int* lvl1){
if (*lvl1 == PWM || *lvl1 == 3){
LCD_Position(0,0);
LCD_PrCString("PWM");
*lvl1 = 0;
}
else if (*lvl1 == PGA){
LCD_Position(0,0);
LCD_PrCString("PGA");
}
else if (*lvl1 == ADC){
LCD_Position(0,0);
LCD_PrCString("ADC");
}
}
void main(void)
{
UI_ELEMENT userInterface[FIRST_LEVEL][SECOND_LEVEL];
int level_1_steper = PWM;
int i;
M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts
PWM8_EnableInt();
LCD_Start();
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);
initialize_LCD(); // set 'PWM' for upper row, '< select >' for lower row
while (1){
if (buttonRightPressed == 1){
for ( i = 0; i < 350; i++);
level_1_steper++;
update_LCD(&level_1_steper);
buttonRightPressed = 0;
// enable button interrupt again
M8C_EnableIntMask(INT_MSK0, INT_MSK0_GPIO);
}
}
}
Problem resolved! As usually solution is quite simple: use GPIO interrupt but test which button has been pressed. GPIO iterrupt:
void buttonInt(void){ // disable button interrupt
M8C_DisableIntMask(INT_MSK0, INT_MSK0_GPIO);
if (Right_Data_ADDR & Right_MASK) buttonRightPressed = 1;
if (Left_Data_ADDR & Left_MASK) buttonLeftPressed = 1;
if (Select_Data_ADDR & Select_MASK) buttonSelectPressed = 1;
}

Resources