Raspberry PI to AVR attiny26 via SPI - three wire mode, garbled output - avr

I have Raspberry PI 3 connected via SPI to AVR Attiny26, which in turn has a LCD connected to it. I am trying to get the SPI running,
Now, the issue is that when I set up the AVR for two wire mode and don't configure pull-up on PB1 (MISO commented out):
USICR = (1<<USIOIE)|(1<<USIWM1)|(1<<USICS1); // Enable USI interrupt - USIOIE=1
// Three wire mode USIWM1=0, USIWM0=1
// Two wire mode USIWM1=1, USIWM0=0
// External clock USICS1=1
//PORTB |= (1<<SPI_MISO); // Enable pull-ups on SPI port
DDRB = 0b01001010; /* Set PORTB bits: 7-4 as input
-- PB7 - Pushbutton (KEY1)/RESET
-- PB6 - Pushbutton (KEY2)/INT0
-- PB5 - ADC8 (T2)
-- PB4 - ADC7 (T1)
-- PB3 - PUMP
-- PB2 - SCK - 0 = external clock (input)
-- PB1 - MISO (output)
-- PB0 - MOSI (input) - */
ISR(USI_OVF_vect) {
disp[counter++] = USIDR;
if(counter==16)
counter = 0;
USISR |= (1<<USIOIF);
}
I get the string transfered and printed on the LCD.
However, when I change the AVR to work in three wire mode and/or enable PB1 pull-up, all I get is garbage. Neither the received characters match the ones sent, nor does their count.
Raspberry is the master here, providing all the clocking, the setup there is always the same (default, three wire mode) and the clock is reasonably slow.
int main(int argc, char **argv) {
int res = bcm2835_init();
printf("BCM2835 Init() = %d\n", res);
res = bcm2835_spi_begin();
printf("BCM2835 Begin() = %d\n", res);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536);
char data[16];
sprintf(data,"%s","<--Some data-->");
int len = strlen(data);
printf("Sent: %s\n", data);
bcm2835_spi_writenb(data, len);
exit(0);
}
Same results with spidev_test program using ioctl, so does not seem related to the library/Pi's program.
On top, what is puzzling me is that when I disconnect the wire from PB1 (MISO), I immediately start receiving garbage from Pi. As if Pi's SPI immediately starts clocking when PB1/MISO goes afloat.
What am I missing here?

Regretfully, I have to say that this one goes into the RTFM category.
After some reserch I found that Pi GPIO works with +3.3V. The Attiny was set to use+ 5V. After rewiring the AVR to work with 3.3V as well, everything seems to be working.
The reason why it worked in two wire mode is the absence of AVR's pull-up resistors (external required), which allowed Pi to use its own and drive the AVR pins in the range acceptable to both Pi and AVR. Enabling pull-ups on AVR would drive Pi's GPIO over the limit. Apparently no damage done, only unpredictable and hard to explain behavior.

Related

How to send AT commands to ESP32 LilyGo-T-Call-SIM800?

I've been working with a LilyGo-TCall-SIM800 module for several days, trying to get out of a dead end.
I have tried an example from "random nerd tutorials" which works correctly. The module connects to the internet and can send data to the cloud.
I have the problem to send AT commands to the SIM800L chip integrated in the module. I can't get the chip to react back.
I have tried using Serial1 and Serial2. I have also tried configuring the RX and TX transmission pins, and I have tried with different baudrates. Always with negative results... when sending the "AT\r" command to the SIM800L, it should return "OK". But it never does.
I have simplified the code as much as possible to minimize errors:
/*
Name: TestAT.ino
Created: 08/12/2022 23:15:28
Author: user
*/
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
// Comunications between ESP32 and SIM800L
#define SerialAT Serial1
//Comunications between ESP32 ans SIM800L go thought TX and RX pins on Serial1 Port
#define MODEM_RX1 16
#define MODEM_TX1 17
void setup() {
// Set console baud rate
SerialMon.begin(115200);
delay(1000);
//Set SerialAT baud rate
SerialAT.begin(38400, SERIAL_8N1, MODEM_RX1, MODEM_TX1);
//Set timeLimit for SerialAT reads
SerialAT.setTimeout(2000);
}
void loop() {
String returned = "";
char ATcommand[] = { 'A','T','\r' };
SerialAT.print(ATcommand);
delay(1000);
returned = SerialAT.readString();
SerialMon.print(millis());
SerialMon.print(" - ");
SerialMon.print(ATcommand);
SerialMon.print(" - SerialAT returned:");
SerialMon.println(returned);
}
Anybody can help me out on this? Any idea or sugestion?
Thanks in advance

UART program for PIC18f65k40

I'm trying to program my MCU in mickroc still I do not get a output.
Is there any difference between PIC18f65k40 and PIC18f65k22 in terms of initiating uart transmission? Whether there is any need to initiate or disable any special registers in PIC18f65k40?
In mikroc software there present a library for uart so I just copied the program from mickroe website and add my transmitter and receiver pins(RX4PPS = 0x11; and TX4PPS = 0x10;)in program by configuring portc as output but my circuit does not work.
char i ;
void main()
{
TRISC = 0b00000000;// making port as output
RX4PPS = 0x11;
TX4PPS = 0x10;
UART4_Init(9600); // Initialize USART module
// (8 bit, 9600 baud rate, no parity bit...)
delay_ms(500);
UART4_Write_Text("Hello world!");
UART4_Write(13); // Start a new line
UART4_Write(10);
UART4_Write_Text("PIC18F65K40 UART example");
UART4_Write(13); // Start a new line
UART4_Write(10);
while (1) {
if (UART4_Data_Ready()) { // If data has been received
i = UART4_Read(); // read it
UART4_Write(i); // and send it back
}
}
}
The PIC18F65k22 has only 2 UARTs and you are working with UART4. I guess the library don't support the controller. Better write the code on your own. There are some examples in the datasheet.

Using Ultrasonic sensor HC-SR04 and Gps (neogps 6m) together on arduino uno

I am trying to read data from both the sensor and the gps (one by one is ok). The sensors work well individually but the Ultrasonic sensor does not give any output. I am new to arduino so i just mixed the codes from the two examples using NewPing Library and TinyGPS libraries. Here is the code. Please suggest what additions need to be made to the code to make both devices work together.
/*********************
*10 to GPS Module TX*
*09 to GPS Module RX*
*********************/
// 1.TESTED USING LED
// 2. added ultrasound libraries
#include <NewPing.h>
#define TRIGGER_PIN 5 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 4 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
#include <SoftwareSerial.h>
#include <TinyGPS.h>
SoftwareSerial mySerial(10, 11);
TinyGPS gps;
float gpsdump(TinyGPS &gps);
void setup()
{
// Oploen serial communications and wait for port to open:
Serial.begin(9600);
// set the data rate for the SoftwareSerial port
mySerial.begin(9600);
delay(1000);
}
void loop() // run over and over
{
bool newdata = false;
unsigned long start = millis();
// Every 5 seconds we print an update
while (millis() - start < 5000)
{
if (mySerial.available())
{
char c = mySerial.read();
//Serial.print(c); // uncomment to see raw GPS data
if (gps.encode(c))
{
newdata = true;
break; // uncomment to print new data immediately!
}
}
}
if (newdata)
{
Serial.println("Acquired Data");
Serial.println("-------------");
gpsdump(gps);
Serial.println("-------------");
Serial.println();
}
}
float gpsdump(TinyGPS &gps)
{
// On Arduino, GPS characters may be lost during lengthy Serial.print()
// On Teensy, Serial prints to USB, which has large output buffering and
// runs very fast, so it's not necessary to worry about missing 4800
// baud GPS characters.
Serial.println("speed");
Serial.println(gps.f_speed_kmph()) ;
Serial.print(sonar.ping_cm());
;
}
The main problems:
You cannot wait 5 seconds without processing the characters. The Arduino receive buffer only has room for 64 characters. The GPS device could have sent 5000 characters during that time, so most of them will get dropped. This prevents the GPS library from ever parsing a complete sentence.
A ping will interfere with software serial ports. You will have to wait for the GPS quiet time to do the ping. Otherwise, the ping process will cause characters to be lost.
Other problems:
You are printing the speed value even though it may not be valid. If you are not moving, or you do not have good satellite reception, the GPS device may not provide a speed.
The Arduino millis() clock will not be synchronized with the GPS clock. You could use the GPS updates as an exact 1-second clock. Simply count 5 fixes as they arrive, and this will mean that 5 seconds have elapsed.
You should use a different serial port and/or library.
This answer describes the various choices: HardwareSerial (i.e. Serial on pins 0 & 1), AltSoftSerial (8 & 9 on an UNO) or NeoSWSerial (any two pins).
Here is a NeoGPS version of your sketch that addresses these issues:
/*********************
*10 to GPS Module TX*
*09 to GPS Module RX*
*********************/
// 1.TESTED USING LED
// 2. added ultrasound libraries
#include <NewPing.h>
#define TRIGGER_PIN 5 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 4 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
#include <NeoSWSerial.h>
#include <NMEAGPS.h>
NeoSWSerial gpsPort(10, 11);
NMEAGPS gps; // the parser
gps_fix fix; // all the parsed values from GPS
uint8_t fixCount = 0; // a one-second "clock"
float gpsdump();
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
// set the data rate for the SoftwareSerial port
gpsPort.begin(9600);
delay(1000);
}
void loop() // run over and over
{
// Check for available GPS characters and parse them
if (gps.available( gpsPort ))
{
// Once per second, a complete fix structure is ready.
fix = gps.read();
fixCount++;
// The GPS device is going to be quiet for a while,
// *now* is a good time to do a ping.
Serial.print( "ping " );
Serial.println( sonar.ping_cm() );
// Every 5 seconds we print an update
if (fixCount >= 5)
{
fixCount = 0; // reset counter
Serial.println("Acquired Data");
Serial.println("-------------");
gpsdump();
Serial.println("-------------");
Serial.println();
}
}
}
float gpsdump()
{
// On Arduino, GPS characters may be lost during lengthy Serial.print()
// On Teensy, Serial prints to USB, which has large output buffering and
// runs very fast, so it's not necessary to worry about missing 4800
// baud GPS characters.
Serial.println("speed ");
if (fix.valid.speed)
Serial.println( fix.speed_kph() );
}
If you want to try it, NeoGPS, AltSoftSerial and NeoSWSerial are available from the IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries. NeoGPS is smaller, faster, more reliable and more accurate than all other libraries.
Even if you don't use it, there are many suggestions on the Installation and Troubleshooting pages.

TWI on ATMega 2560 wait's in infinity loop

I get some stupid error's if I want to try initialise the connection from the TWI master to the bus. The start condition will be send but the processor waits in the infinity loop bevor starting to send the slave address to the bus.
I also have analysed the signals on the bus and one result is that the clock is running but there will be no data send on the bus.
The processor wait's in the line with the marked arrow.
We use the following code to start the and initialise the bus ...
void i2c_master_init() {
TWBR = (uint8_t)TWBR_val;
}
void i2c_master_stop() {
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}
uint8_t i2c_master_start(uint8_t address) {
TWCR = 0;
TWCR |= (1<<TWSTA);
TWCR |= (1<<TWEN);
TWCR |= (1<<TWINT);
while( !(TWCR & (1<<TWINT)) ); <--
[...]
}
Currently I don't know, what's going wrong with the code. Or am I doing something else wrong. Can anyone help me?
Thank you in anticipation.
My best guess without hardware on my bench is that you should set all flags to TWI control registry at once by TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN). Meanwhile you set them one by one in 3 separate operations (multiple clock cycles), while datasheet implicitly says flags must be set together, see also datasheet examples.

Display ADC result on LCD or Terminal using CodevisionAVR

My project is an audio spectrum analyzer, but I am stuck in displaying the ADC results, either on my LCD or on the Terminal of CodevisionAVR.
The project uses an ATmega16A, with an 7.37 MHz external oscillator. For an IDE I am using CodevisionAVR.
The audio spectrum analyzer takes its input through a 3.5 mm jack audio cable, this signal is amplified and filtered in order to select the frequencies between 0 and 4 KHz, and the output of this circuit is connected to PA0, which is the channel 0 of the ADC of the microcontroller.
For testing, I have set the ADC to work on 8 bits (read the most significant 8 bits), taking the internal 2.56V as voltage reference. I have decoupled AREF pin using a 10nF capacitor (I will change it to 100nF for a better noise reduction). The ADC is also in free running mode.
I am stuck in displaying the ADC results, either on my LCD or on the Terminal of CodevisionAVR (through the UART --- configured using the wizard).
This is the function I used for the ADC:
// Voltage Reference: Int., cap. on AREF
#define ADC_VREF_TYPE ((1<<REFS1) | (1<<REFS0) | (1<<ADLAR))
// Read the 8 most significant bits
// of the AD conversion result
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);
// Wait for the AD conversion to complete
while ((ADCSRA & (1<<ADIF))==0);
ADCSRA|=(1<<ADIF);
return ADCH;
}
Main function of the code:
void main (void)
{
Init_Controller(); // this must be the first "init" action/call!
#asm("sei") // enable interrupts
lcd_init(16);
lcd_gotoxy(0,1);
lcd_putsf("AUDIO SPECTRUM");
delay_ms(3000);
lcd_clear();
while(TRUE)
{
wdogtrig();
TCNT1 = 0; //usage of Timer1 with OCR1A
TIFR |= 1<<OCF1A;
for(i=0;i<N;i++) {
while((TIFR & (1<<OCF1A)) == 0)
putchar(read_adc());
//adc_set[i] = adc_read(); //this is a second option
TIFR |= 1<<OCF1A;
}
//for(i=0; i<N; i++)
//printf("adc values: %d \n",adc_set[i]);
} //end while loop
}
N is defined as 32 = number of samples in 1 AD conversion.
The first error I see is using putchar() to write a number to the LCD.
The result of read_adc() is a number, not a string of ascii characters. You need to use sprintf to write the ADC result as a string into a buffer, then use lcd_putsf() to send the buffer to the LCD.

Resources