Losing data bit when reading from GPIO by libgpiod on Linux - c

I am using Debian (8.3.0-6) on an embedded custom board and working on the dht11 sensor.
Briefly,
I need to read 40 bits from a GPIO pin and each bit can take a max 70 microseconds. When bit-level is high for max 28us or 70us, it means is logic 0 or 1, respectively. (So I have a timeout controller for each bit and if a bit takes more than 80us, I need to stop the process.).
In my situation, sometimes I can read all 40 bits correctly but sometimes I can't do it and the function of libgpiod gpiod_line_get_value(line); is missing the bit (my code is below). I am trying to figure out that why I cant read and lose a bit, what is the reason for that. But I haven't found a sensible answer yet. So I was wondering What am I missing out?, What is the proper way to GPIO programming?
Here is what I wanted to show you, How do I understand what I am missing a bit? Whenever I catch a bit, I am setting and resetting another GPIO pin at the rising and falling edge of a bit (So I can see which bit missing). Moreover, as far as I see I am always missing the two edges on one bit or one edge on two bits consecutively (rising and falling or falling and rising). In the first picture, you can see which bit I missed, the second is when I read all bits correctly.
Here it is my code:
//********************************************************* Start reading data bit by low level (50us) ***************************
for (int i = 0; i < DHT_DATA_BYTE_COUNT ; i++) //DHT_DATA_BYTE_COUNT = 5
{
for (int J = 7; J > -1; J--)
{
GPIO_SetOutPutPin(testPin); //gpiod_line_set_value(testPin, 1);
int ret;
start = micros();
do
{
ret = GPIO_IsInputPinSet(dht11pin);//gpiod_line_get_value(dht11pin);
delta = micros() - start;
if(ret == -1)
{
err_step.step = 9;
err_step.ret_val = -1;
return -1;
}
if(delta > DHT_START_BIT_TIMEOUT_US) //80us
{
err_step.step = 10;
err_step.ret_val = -2;
err_step.timestamp[is] = delta;
err_step.indx[is].i = i;
err_step.indx[is++].j = J;
GPIO_ResetOutPutPin(testPin);
return -2;
}
}while(ret == 0);
GPIO_ResetOutPutPin(testPin);
err_step.ret_val = 10;
GPIO_SetOutPutPin(testPin);
start = micros();
do
{
ret = GPIO_IsInputPinSet(dht11pin);
delta = micros() - start;
if(ret == -1)
{
err_step.step = 11;
err_step.ret_val = -1;
return -1;
}
if(delta > DHT_BEGIN_RESPONSE_TIMEOUT_US) //80us
{
err_step.step = 12;
err_step.ret_val = -2;
err_step.timestamp[is] = delta;
err_step.indx[is].i = i;
err_step.indx[is++].j = J;
return -2;
}
}while(ret == 1);
err_step.timestamp[is] = delta;
err_step.indx[is].i = i;
err_step.indx[is++].j = J;
GPIO_ResetOutPutPin(testPin);
err_step.ret_val = 10;
(delta > DHT_BIT_SET_DATA_DETECT_TIME_US) ? bitWrite(dht11_byte[i],J,1) : bitWrite(dht11_byte[i],J,0);
}
}

Related

Optimizing a read statement

I have build a led cube using transistors, shift registers and an arduino nano (and it kinda works). I know shift registers may be a poor design choice but I have to work with what I got so please don't get stuck on that in your answers.
There is this piece of code:
bool input[32];
void resetLeds()
{
input[R1] = 0;
input[G1] = 0;
input[B1] = 0;
input[R2] = 0;
input[G2] = 0;
input[B2] = 0;
input[R3] = 0;
input[G3] = 0;
input[B3] = 0;
input[R4] = 0;
input[G4] = 0;
input[B4] = 0;
input[X1Z1] = 1;
input[X1Z2] = 1;
input[X1Z3] = 1;
input[X1Z4] = 1;
input[X2Z1] = 1;
input[X2Z2] = 1;
input[X2Z3] = 1;
input[X2Z4] = 1;
input[X3Z1] = 1;
input[X3Z2] = 1;
input[X3Z3] = 1;
input[X3Z4] = 1;
input[X4Z1] = 1;
input[X4Z2] = 1;
input[X4Z3] = 1;
input[X4Z4] = 1;
}
void loop()
{
T = micros();
for(int I = 0; I < 100; I++)
{
counter++;
if(counter >= 256 / DIVIDER) counter = 0;
for(int i = 0; i < 64; i += 4)
{
x = i / 16;
z = (i % 16) / 4;
resetLeds();
input[XZ[x][z]] = 0;
for(y = 0; y < 4; y++)
{
index = i + y;
if(counter < xyz[index][0]) input[Y[y][RED]] = 1;
if(counter < xyz[index][1]) input[Y[y][GREEN]] = 1;
if(counter < xyz[index][2]) input[Y[y][BLUE]] = 1;
}
PORTB = 0;
for(int j = 0; j < 32; j++)
{
bitWrite(OUT_PORT, 4, 0);
bitWrite(OUT_PORT, 3, input[j]);
PORTB = OUT_PORT;
bitWrite(OUT_PORT, 4, 1);
PORTB = OUT_PORT;
}
bitWrite(OUT_PORT, 0, 1);
PORTB = OUT_PORT;
}
}
T = micros() - T;
Serial.println(T / 100);
}
The runtime of a single iteration is reported to be 1274 microseconds, but I need it to be even lower to build a pwm function of sorts (manually turning a transistor on and off through a shift register). While optimizing I found this strange behavior I cannot explain. There is this line in the code:
bitWrite(OUT_PORT, 3, input[j]);
When I remove this line or change input[j] to 0 the runtime is halved. Apparently, an array lookup takes about 20 microseconds. But I find it very weird since I am indexing this array in more places in the code (when writing) and there it takes 23 microseconds for 28 writes.
Can somebody please explain to me what is going on and/or how to make this piece of code run faster? I guess you can do writes in a pipelined manner but a read stalls the code completely since you cannot continue before you receive the value from cache. But then again, I hardly doubt a read from cache should take 23 whole microseconds.
[EDIT 27/10/2020 16:55]
The part of the code that writes to the shiftregisters has a lot of bitWrites which are time consuming. Instead of writing the bits every time I implemented preconfigured options for the byte to write to PORTB:
PORTB = LATCH_LOW;
for(int j = 0; j < 32; j++)
{
if(input[j] == 0)
{
PORTB = CLOCK_OFF_DATA_0;
PORTB = CLOCK_ON_DATA_0;
}
else
{
PORTB = CLOCK_OFF_DATA_1;
PORTB = CLOCK_ON_DATA_1;
}
}
PORTB = LATCH_HIGH;
This cuts my running time roughly in half, which is kind of fast enough but I wonder I could get it to run even faster. When I remove everything from the loop except for the writing to the shift registers and I remove the input[j] read, I get a runtime of 200 microseconds. This means that if I could remove dependence on the input[j] read and compute its value inline I should be able to get at least another 2 times speed up. To achieve 8 bit PWM I calculated I need the running time to be 40 microseconds or less so I am going to stick with 16 (instead of 256) brightness levels for now to prevent flicker.
[EDIT 28/10/2020 19:38]
I went into the platform.txt and change the optimization flag to -Ofast. This got my iteration time down another 200 microseconds!

Struggle to program an LFO

based on some tutorial code I've found I coded a little synthesizer with three oscilators and four different waveform. It works well and I want to add an LFO to module the sounds. Since I didn't coded everything on my own I'm a bit confused of how I could fit the LFO formula on my code. This is more or less what I tried in order to implement the LFO formula on a sinewave.(This formula is something like this: sinewaveFormula + 0.5 * Sinefreq * sin(2pi*1) * time)
double normalize(double phase)
{
double cycles = phase/(2.0*pi);
phase -= trunc(cycles) * 2.0 * pi;
if (phase < 0) phase += 2.0*pi;
return phase;
}
double sine(double phase)
{ phase = normalize(phase); return (sin(phase));}
static void build_sine_table(int16_t *data, int wave_length) {
double phase_increment = (2.0f * pi) / (double)wave_length;
double current_phase = 0;
for(int i = 0; i < wave_length; i++) {
int sample = synthOsc(current_phase, oscNum, selectedWave, selectedWave2, selectedWave3, intensity, intensity2, intensity3) + 0.5 * ((current_phase* wave_length) / (2*pi)) * sin(2*pi*(1.0)) * wave_length;
data[i] = (int16_t)sample;
current_phase += phase_increment;
}
}
static void write_samples(int16_t *s_byteStream, long begin, long end, long length) {
if(note > 0) {
double d_sample_rate = sample_rate;
double d_table_length = table_length;
double d_note = note;
// get correct phase increment for note depending on sample rate and table length.
double phase_increment = (get_pitch(d_note) / d_sample_rate) * d_table_length;
// loop through the buffer and write samples.
for (int i = 0; i < length; i+=2) {
phase_double += phase_increment;
phase_int = (int)phase_double;
if(phase_double >= table_length) {
double diff = phase_double - table_length;
phase_double = diff;
phase_int = (int)diff;
}
if(phase_int < table_length && phase_int > -1) {
if(s_byteStream != NULL) {
int16_t sample = sine_waveform_wave[phase_int];
target_amp = update_envelope();
if(smoothing_enabled) {
// move current amp towards target amp for a smoother transition.
if(current_amp < target_amp) {
current_amp += smoothing_amp_speed;
if(current_amp > target_amp) {
current_amp = target_amp;
}
} else if(current_amp > target_amp) {
current_amp -= smoothing_amp_speed;
if(current_amp < target_amp) {
current_amp = target_amp;
}
}
} else {
current_amp = target_amp;
}
sample *= current_amp; // scale volume.
s_byteStream[i+begin] = sample; // left channel
s_byteStream[i+begin+1] = sample; // right channel
}
}
}
}
}
The code compile but there's no LFO on the sine. I don't understand how I could make this formula work with this code.
It may help to get a basic understanding of how a LFO actually works. It is not that difficult - as an LFO is just another oscillator that is mixed to the waveform you want to modulate.
I would suggest to remove your LFO formular from your call of synthOsc(), then you get a clean oscillator signal again. As a next step, create another oscillator signal for which you can use a very low frequency. Mix both signals together and you are done.
Expresssed in simple math, it is like this:
int the_sample_you_want_to_modulate = synthOsc1(...);
int a_sample_with_very_low_frequency = synthOsc2(...);
Mixing two waveforms is done through addition:
int mixed_sample = the_sample_you_want_to_modulate + a_sample_with_very_low_frequency;
The resulting sample will sweep now based on the frequency you have used for synthOsc2().
As you can see, to implement an LFO you actually do not need a separate formular. You already have the formular when you know how to create an oscillator.
Note that if you add two sine oscillators that have the exact same frequency, the resulting signal will just get louder. But when each has a different frequency, you will get a new waveform. For LFOs (which are in fact just ordinary oscillators - like in your build_sine_table() function) you typically set a very low frequency: 1 - 10 Hz is low enough to get an audible sweep. For higher frequencies you get chords as a result.

The ADC buffer not hold the full value

I am trying to read the ADC value from the potentiometer in PIC24F Curiosity Development Board (PIC24FJ128GA204) then turn on the LED if the value more 1000 (I configured it as a 10-bit).
However, The maximum value that place in the buffer is around 500. The following code shows the problem.
Please advise.
#include <xc.h>
#define Pot_TriState _TRISC0
#define Pot_AnalogState _ANSC0
int main(void) {
Pot_TriState = 1;
Pot_AnalogState = 1;
_TRISC5 = 0;
_LATC5 = 0;
ADC_Config();
while (1) {
if (ADC1BUF10 >= 1000) {
_LATC5 = 0; //Never be executed
}
if (ADC1BUF10 >= 300) {
_LATC5 = 1;
}
}
return 0;
}
void ADC_Config() {
AD1CON1bits.ADON = 0; // ADC must be off when changing configuration
//start conversion automatically after sampling and configure ADC to either 10 or 12 bits
AD1CON1bits.SSRC = 7;
AD1CON1bits.MODE12 = 0;
AD1CON2bits.PVCFG = 0; //A/D Converter Positive Voltage Reference Configuration bits
AD1CON2bits.NVCFG0 = 0; // A/D Converter Negative Voltage Reference Configuration bit
AD1CHSbits.CH0SB = 0b01010; //01010 = AN10
AD1CHSbits.CH0SA = 0b01010; //added
AD1CON3bits.ADRC = 1; // 1 = RC clock --- ADC?s internal RC clock
AD1CON3bits.SAMC = 0b11111; // set auto sampling time -- Auto-Sample Time Select bits11111 = 31 TAD
AD1CON2bits.BUFREGEN = 1; //Conversion result is loaded into the buffer location determined by the converted channel
AD1CON1bits.ASAM = 1;
AD1CON1bits.ADON = 1;
}

C, can't compare two buffers

I am working with some C code and I'm totally stuck in this function. It should compare two buffers with some deviator. For example if EEPROM_buffer[1] = 80, so TxBuffer values from 78 to 82 should be correct!
So the problem is that it always returns -1. I checked both buffers, data is correct and they should match, but won't. Program just runs while until reach i = 3 and returns -1..
I compile with atmel studio 6.1, atmel32A4U microcontroller..
int8_t CheckMatching(t_IrBuff * tx_buffer, t_IrBuff * tpool)
{
uint8_t i = 0;
uint16_t * TxBuffer = (uint16_t*) tx_buffer->data;
while((TxBuffer->state != Data_match) || (i != (SavedBuff_count))) // Data_match = 7;
{
uint16_t * EEPROM_buffer = (uint16_t*) tpool[i].data;
for(uint16_t j = 0; j < tpool[i].usedSize; j++) // tpool[i].usedSize = 67;
{
if(abs(TxBuffer[j] - EEPROM_buffer[j]) > 3)
{
i++;
continue;
}
}
i++;
TxBuffer->state = Data_match; // state value before Data_match equal 6!
}
tx_buffer->state = Buffer_empty;
if(i == (SavedBuff_count)) // SavedBuff_count = 3;
{
return -1;
}
return i;
}
Both your TxBuffer elements and EEPROM_buffer elements are uint16_t. When deducting 81 from 80 as uint16_t it would give 0xffff, with no chance of abs to help you. Do a typecast to int32_t and you will be better off.

How Can I change objects name by a loop in C lang?

How Can I change objects name by a loop?
I want create a light effect like knight-rider's one. With a PIC
I thought instead of turning on and off manually to use a loop for change RB line number.
I want to change the last number of this Port line name: like RB01 RB02 like this
my code is like this
for(int i = 0; i>6 ; i++ ){
PORTB = 0X00;
RB+i = 1;
}
Are there any kind of method do something like this? thanks
Assuming RB01, RB02, etc are just convenient #defines for accessing the bits in PORTB, you can write the loop with bitwise arithmetic and not use RB0* at all.
for ( int i = 0; i != 6; ++ i ) {
PORTB = 1 << i; /* one light at a time */
/* or */
PORTB = ( 1 << i + 1 ) - 1; /* light all in sequence */
}
It's not very elegant, but one way is to do it like this:
PORTB = 0x00;
for (i = 0; i < 6; ++i)
{
RB00 = (i == 0);
RB01 = (i == 1);
RB02 = (i == 2);
RB03 = (i == 3);
RB04 = (i == 4);
RB05 = (i == 5);
// note: you probably want to put a delay in here, e.g. 200 ms
}
If you want to keep the previous LEDs on each time you turn on a new one then you can do that like this:
PORTB = 0x00;
for (i = 0; i < 6; ++i)
{
RB00 = (i >= 0);
RB01 = (i >= 1);
RB02 = (i >= 2);
RB03 = (i >= 3);
RB04 = (i >= 4);
RB05 = (i >= 5);
// note: you probably want to put a delay in here, e.g. 200 ms
}
No, there is no way to "generate" symbol names that way. You can use bit masks for manipulating the latch register of the port in question.
I would probably use a table:
struct portbits
{
sometype bit; // Not quite sure what "RB0..RB5" actually translate to.
};
struct portbits bits[] =
{
RB00,
RB01,
RB02,
RB03,
RB04,
RB05,
RB06,
RB07,
};
for(i = 0; i < 7; i++)
{
bits[i] = 1;
}

Resources