int led_pin = 9;
int duty_cycle = 63; //in %
int freq_OC = 16000; //in Hz
int freq_clk = 16000000; //in Hz
int prescaler = 1;
void setup() {
//setting the port B pin (D9) as output for OC1A to override the normal port functionality
DDRB = DDRB|(1 << led_pin);
//clearing the counter/timer registers
TCCR1A = 0;
TCCR1B = 0;
//setting the prescaler 1
TCCR1B = TCCR1B|(1 << CS10);
//setting the mode 14 fast PWM
TCCR1B = TCCR1B|((1 << WGM13)|(1 << WGM12));
TCCR1A = TCCR1A|(1 << WGM11);
//setting the fast PWM in non-inverting mode
TCCR1A = TCCR1A|(1 << COM1A1);
ICR1 = (freq_clk/(freq_OC*prescaler)) - 1;
OCR1A = ICR1/(100/duty_cycle);
}
void loop() {
}
Why doesn't this code work when pin D9 is initialised as an output pin OC1A as written above? But it works when...
DDRB = DDRB|(1 << PB1);
Is there any reason for this? As far as the datasheet for ATMEGA328P is concerned, it quotes "If one or both of the COM1X1:0 bits are written to one, the OC1X overrides the normal port functionality of the I/O pin it is connected to". So does that mean the PB1 (or D9) pin no longer functions as an I/O pin and therefore I cannot initialise it with a variable name?
DDRB is an 8-bit register, it has no 9th bit in it.
You have led_pin variable set to 9, therefore operation DDRB = DDRB|(1 << led_pin) has no effect.
There is no D9 pin on the ATmega328P. But looks like you're talking about Arduino board. You can google "Arduino UNO Pinout". E.g. this
You can see D9 pin of the board is connected to PB1 pin of the MCU. Therefore you have to use DDRB |= (1 << 1) (use value 1, not 9)
Related
I have an Arduino Nano 33 iot that outputs data via Serial at 38400 baud, connected via USB. Setup starts with Serial.Begin. The Raspberry Pi 4, running Raspian buster is set up to receive the data. It can see the correct port, /dev/ttyACM0, but nothing comes in.
I even installed the correct Arduino IDE and SAMD board package on the Raspberry Pi. It still does not find it until after the IDE uploads the replacement sketch and the CPU is reset. The IDE can grab the serial number and board type though. I can then exit out of the IDE and the Arduino is still pumping out serial to the Raspberry Pi.
The only other way to make it work is by pressing the reset button on the Arduino every time a reboot is done on the Raspberry Pi. Serial was tested on the Pi using screen.
Neither of these options are convenient. What am I missing?
/*
Connects via I2C to a CMPS14, outputs NMEA0183 HDM sentences via Serial (38400 baud)
By James Henderson, 2014, adapted to output NMEA sentences by Ian Van Schaick
*/
#include <Keyboard.h>
#include <Wire.h>
#define CMPS14_ADDRESS 0x60 // Address of CMPS14 shifted right one bit for arduino wire library
#define ANGLE_8 1 // Register to read 8bit angle from
unsigned char high_byte, low_byte, angle8;
signed char pitch, roll;
float angle16;
int fine;
float bearingH; // Holds whole degrees of bearing
float bearingL; // Holds decimal digits of bearing
int bearing;
char nbsp;
char mystring[25];
char mystring2[25];
char mystring3[25];
int software;
int cal;
unsigned int _last_status;
uint8_t checksum(char *s)
{
uint8_t c = 0;
while (*s)
c ^= *s++;
return c;
}
void CMPS14_eraseProfil()
{
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0xE0);
_last_status = Wire.endTransmission();
delay(20); // 20ms delay after each of the three bytes send
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0xE5);
_last_status = Wire.endTransmission();
delay(20); // 20ms delay after each of the three bytes send
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0xE2);
_last_status = Wire.endTransmission();
delay(20); // 20ms delay after each of the three bytes send
}
//Correct heading for known deviation
int DeviationCorrect(int Head)
{
return 0;
}
void setup() {
Serial.begin(38400); // Start serial port
Wire.begin();
nbsp = 32;
// CMPS14_eraseProfil();
}
void loop() {
Wire.beginTransmission(CMPS14_ADDRESS); //starts communication with CMPS14
Wire.write(ANGLE_8); //Sends the register we wish to start reading from
Wire.endTransmission();
// Request 5 bytes from the CMPS14
// this will give us the 8 bit bearing,
// both bytes of the 16 bit bearing, pitch and roll
Wire.requestFrom(CMPS14_ADDRESS, 26);
while (Wire.available() < 26); // Wait for all bytes to come back
// software = Wire.read();
// Serial.print("Version: ");
// Serial.println(software);
angle8 = Wire.read(); // Read back the 5 bytes
high_byte = Wire.read();
low_byte = Wire.read();
pitch = Wire.read();
roll = Wire.read();
// int i = 6;
// while (i <= 25) {
// Wire.read();
// i++;
// }
//
// cal = Wire.read();
// Serial.print("Cal: ");
// Serial.println(cal);
bearing = ((high_byte << 8) + low_byte) / 10;
fine = ((high_byte << 8) + low_byte) % 10;
byte data[128] = "$HCHDM,";
data[8] = bearing;
// int deviation = 0;
//DeviationCorrect(bearing);
// bearing = bearing;
//+ deviation;
//Print out NMEA 0183 string HDM
snprintf(mystring, sizeof(mystring), "$HCHDM,%d.%d,M", bearing , fine);
uint8_t crc = checksum(mystring + 1);
Serial.print(mystring);
Serial.print("*");
if (crc < 16) Serial.print("0");
Serial.println(crc, HEX);
//Print out NMEA 0183 string XDR for Pitch
snprintf(mystring2, sizeof(mystring2), "$HCXDR,A,%d,D,PITCH", pitch);
uint8_t crc2 = checksum(mystring2 + 1);
Serial.print(mystring2);
Serial.print("*");
if(crc2 < 16) Serial.print("0");
Serial.println(crc2, HEX);
//Print out NMEA 0183 string XDR for Roll/Heel
snprintf(mystring3, sizeof(mystring3), "$HCXDR,A,%d,D,ROLL", roll);
uint8_t crc3 = checksum(mystring3 + 1);
Serial.print(mystring3);
Serial.print("*");
if(crc3 < 16) Serial.print("0");
Serial.println(crc3, HEX);
delay(100);
}
I'm trying to drive the LTC1664 DAC from an Arduino (Mega 2560). The SPI data and clock coming out of the Arduino is always synched (rise and falls) for all 4 modes when the DAC data sheet indicates phasing
I've tried all modes, the SS line on the chip is being brought low during the writes (as it should) and I've tried different speeds and shiftOut(), setClockDivider(), setDataMode(), beginTransaction() and endTransaction().
Is this a bug in Arduino SPI, something specific to the Mega 2560, should I try an Uno or Due? Help please! Code below o-scope traces.
BTW: The 16 bit word I'm trying to transmit is, 0x3600 (o-scope trace truncated).
/*
Test DAC Control
created 18 Mar 2020 (Covid-19, oppsies)
by Danny Holstein
*/
// inslude the SPI library:
#include <SPI.h>
void DAC(unsigned short value, unsigned char channel, int SS_Pin, int model);
enum models{LTC1664};
enum models model;
// set pin 10 as the slave select for the digital pot:
const int DAC_SS_Pin = 22;
void setup() {
// set the DAC_SS_Pin as an output:
// initialize SPI:
Serial.begin(115200);
SPI.begin();
Serial.println("SPI.begin");
pinMode(DAC_SS_Pin, OUTPUT);
}
void loop() {
// go through the six channels of the digital pot:
for (int channel = 1; channel < 6; channel++) {
delay(500);
DAC(128*channel, channel, DAC_SS_Pin, LTC1664);
}
delay(1000);
Serial.println("new loop");
}
/*
DAC Control
This function controls an LTC1664 Micropower Quad 10-Bit DAC.
The LTC1664 is SPI-controlled,and to command it, you send one 16 bit word,
A3 A2 A1 A0 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 X1 X0
| ADDR | INPUT CODE | DON'T CARE
The circuit:
* CS - to digital pin 22 (SS pin)
* SDI - to digital pin 51 (MOSI pin)
* SDO - to digital pin 50 (MISO pin, not used in this function)
* CLK - to digital pin 52 (SCK pin)
created 18 Mar 2020 (Covid-19, oppsies)
by Danny Holstein
*/
void DAC(unsigned short value, unsigned char channel, int SS_Pin, int model) {
// take the SS pin low to select the chip:
digitalWrite(SS_Pin, LOW); delay(100);
unsigned short buf, b16;
unsigned char *c, b; c = (unsigned char *) &buf;
switch (model)
{
case LTC1664:
if (channel > 4) channel = 0xF;
buf = (channel << 12) | ((value & 0x3FF) << 2);
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
b16 = SPI.transfer16(buf);
Serial.print("0x" + String(buf, HEX)); Serial.println("\t0x" + String(b16, HEX) + "\t");
SPI.endTransaction();
break;
default:
break;
}
delay(100);
// take the SS pin high to de-select the chip:
digitalWrite(SS_Pin, HIGH);
// printf("value = 0x%04x", buf);
}
Turns out it wasn't related to the Arduino SPI function or phasing issues, the LTC1664 has a CLR pin that I had attached to a GPIO but had failed to command HIGH, it had been floating and inhibiting the chip, command HIGH and everything is good now.
I am trying to make a sensorless bldc motor control driver. I found an Arduino code and I want to convert it ARM Stm32. But I don't understand totally what happens in ISR interrupt part. Can anyone explain me shortly? Why used bldc_step&1 and when decreased i.
byte bldc_step = 0, motor_speed, pin_state;
void setup()
{
DDRD |= 0xE0; // configure pins 5, 6 and 7 as outputs
PORTD = 0x00;
DDRB |= 0x0E; // configure pins 9, 10 and 11 as outputs
PORTB = 0x31;
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
}
// pin change interrupt 2 (PCINT2) ISR
ISR (PCINT2_vect)
{
if( (PIND & PCMSK2) != pin_state )
return;
// BEMF debounce
for(byte i = 0; i < 20; i++)
{
if(bldc_step & 1){
if(PIND & PCMSK2) i -= 1;
}
else {
if(!(PIND & PCMSK2)) i -= 1;
}
}
bldc_move();
bldc_step++;
bldc_step %= 6;
}
// BLDC motor commutation function
void bldc_move()
{
switch(bldc_step)
{
case 0:
AH_BL();
BEMF_C_FALLING();
break;
case 1:
AH_CL();
BEMF_B_RISING();
break;
case 2:
BH_CL();
BEMF_A_FALLING();
break;
case 3:
BH_AL();
BEMF_C_RISING();
break;
case 4:
CH_AL();
BEMF_B_FALLING();
break;
case 5:
CH_BL();
BEMF_A_RISING();
}
}
PCICR = 4; // enable pin change interrupt for pins PCINT23..16 (Arduino 0 to 7)
void BEMF_A_RISING()
{
PCMSK2 = 0x04; // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
pin_state = 0x04;
}
void BEMF_A_FALLING()
{
PCMSK2 = 0x04; // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
pin_state = 0;
}
void BEMF_B_RISING()
{
PCMSK2 = 0x08; // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
pin_state = 0x08;
}
void BEMF_B_FALLING()
{
PCMSK2 = 0x08; // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
pin_state = 0;
}
void BEMF_C_RISING()
{
PCMSK2 = 0x10; // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
pin_state = 0x10;
}
void BEMF_C_FALLING()
{
PCMSK2 = 0x10; // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
pin_state = 0;
}
void AH_BL()
{
PORTD &= ~0xA0;
PORTD |= 0x40;
TCCR1A = 0; // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void AH_CL()
{
PORTD &= ~0xC0;
PORTD |= 0x20;
TCCR1A = 0; // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void BH_CL()
{
PORTD &= ~0xC0;
PORTD |= 0x20;
TCCR2A = 0; // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void BH_AL()
{
PORTD &= ~0x60;
PORTD |= 0x80;
TCCR2A = 0; // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void CH_AL()
{
PORTD &= ~0x60;
PORTD |= 0x80;
TCCR2A = 0; // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void CH_BL()
{
PORTD &= ~0xA0;
PORTD |= 0x40;
TCCR2A = 0; // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void SET_PWM_DUTY(byte duty)
{
OCR1A = duty; // set pin 9 PWM duty cycle
OCR1B = duty; // set pin 10 PWM duty cycle
OCR2A = duty; // set pin 11 PWM duty cycle
}
The speed of the motor depends of the applied voltage D.V where the D is the duty.
Fm = D.VP.KV.poles/120 = D.Vp/M
Tm = M/(D.Vp)
The ideal delay after bemf detection is 30 deg :
delay = Tm/12 = M/(12.D.Vp) = M'/(D.Vp) : M'=M/12
M' – Volt*seconds for the 30° delay after zero crossing detection.
The comparator ISR is counting up only during on time. As wider is the PWM pulse the faster is the counting.
Loop maximum time:
m = N.ticks.Cycles
Cycles are the ticks per instruction.
Loop is counting (up) to N only during ton on rising or on falling BEMF. The counted PWM pulses will be:
Pc = m/ton or Pc = m/(D.Ts)
The estimated time of the loop is:
dt = Pc.Ts = m.Ts/(D.Ts) = m/D
The required delay and the time of the loop must be equal: delay = dt
M'/(Vp.D) = m/D or m = M'/Vp
This method is also called "Back-EMF Integration Method".
M' = D.Vp.Tm'
is the integrated bemf voltage from ZCP to the next commutation. You can read more
about this briefly here:
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3231115/
Adjusting N and PWM frequency (Fs=1/Ts) can give you almost perfect 30 deg delay after bemf detection. The poles and Kv of the motor should be known. This code will not work with any motor without adjustment.
Cheers
This code is for debouncing the back electromagnetic force (BEMF) signal, equivalent code is in https://github.com/esden/open-bldc-mk/blob/master/bldc.c
ISR(ANA_COMP_vect){
unsigned char i;
/* debounce the bemf signal */
for(i=0; i<BEMF_DEBOUNCE_COUNT; i++){
if(bldc_phase & 1){
if(BEMF_L) i -= BEMF_DEBOUNCE_DEC;
}else{
if(BEMF_H) i -= BEMF_DEBOUNCE_DEC;
}
}
For debouncing and why it is done see https://en.wikipedia.org/wiki/Switch#Contact_bounce
The exact algorithm implemented here is debouncing switches with vertical counters, cf https://www.compuphase.com/electronics/debouncing.htm - Debouncing switches with vertical counters
In bldc_step & 1 the & operator is bitwise AND i.e. 45 & 35 = 33 or 00101101 & 00100011 = 00100001 in binary
bldc_step is a byte and bitwise-ANDing it with 1 is equivalent to testing if the last bit of bldc_step is set. With PIND & PCMSK2 is checked if PIND is high or low
This code and the rest of the debouncing loop implements the vertical counter described in https://www.compuphase.com/electronics/debouncing.htm
I am having trouble with reading data sent from my laptop to the microcontroller via UART. The transmitting part works fine - I can send data to my laptop without problems, but echoing data, or reading keyboard input data from the laptop doesn't work. I have tried to implement reading both with polling and with Rx interrupt routines, but without success. The microcontroller I am using is ATMEGA2560, and I am conntected to my laptop via FTD1232 USB to TTL serial converter.
I am using Putty as a serial comm terminal, and the Arduino IDE for programming.
I am assuming that the problem is not in the hardware based on the following - I have tried initializing different USARTs and tried to use different COM ports, as well as another USB to TTL converter, various wires, but the result is the same. I have also connected another power source to supply enough voltage to all devices.
I am trying to get at least a response by turning a LED on when Rx interrupt occurs (when I type something in the terminal).
~
#define F_CPU 16000000UL //16MHz
#define BAUD 115200UL //bps
#define BAUD_PRESCALER (((F_CPU/(BAUD*8UL)))-1) //Table 101, page 212
volatile uint8_t temp;
void UART_init(){
//Set baud rate
UBRR0H = (uint8_t)(BAUD_PRESCALER >> 8); //Higher portion of the baud rate
UBRR0L = (uint8_t)BAUD_PRESCALER; //Lower portion of the baud rate
//Enable Receiver and Transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
//Set frame format: 8-bit format, 1 stop bit, no parity
UCSR0C |= (3 << UCSZ00);
UCSR0C &= ~(1 << USBS0); //clear for 1 stop bit
//Set Double Speed Asynchronous mode
UCSR0A |= (1 << U2X0);
UCSR0B |= (1 << RXCIE0); //Enables interrupt rxc
}
uint8_t UART_getchar(){
//Wait for RXC flag
while(!(UCSR0A & (1 << RXC0))){};
return UDR0;
}
//Arduino setup()
void setup(){
pinMode(8, OUTPUT);
UART_init();
sei();
}
//Arduino loop()
void loop(){
delay(500);
UART_putchar('a');
}
ISR(USART0_RX_vect){
temp = UDR0;
digitalWrite(8, HIGH);
}
It is a lenghty post, but I tried to be specific and also post the whole code. The datasheet I am using for the ATMEGA2560 can be found here.
My Putty settings:
COM Port Settings
I've just tested it on my Mega board and it's working fine without interrupts enabled (simple loopback):
#define BAUD 115200UL
#define BAUD_PRESCALER (((F_CPU/(BAUD*8UL)))-1)
volatile uint8_t temp;
void UART_init(){
//Set baud rate
UBRR0H = (uint8_t)(BAUD_PRESCALER >> 8); //Higher portion of the baud rate
UBRR0L = (uint8_t)BAUD_PRESCALER; //Lower portion of the baud rate
//Enable Receiver and Transmitter
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
//Set frame format: 8-bit format, 1 stop bit, no parity
UCSR0C |= (3 << UCSZ00);
UCSR0C &= ~(1 << USBS0); //clear for 1 stop bit
//Set Double Speed Asynchronous mode
UCSR0A |= (1 << U2X0);
// UCSR0B |= (1 << RXCIE0); //Enables interrupt rxc
}
uint8_t UART_getchar(){
//Wait for RXC flag
while(!(UCSR0A & (1 << RXC0))){};
return UDR0;
}
void UART_putchar(uint8_t data){
//Do nothing until UDR is ready
while(!(UCSR0A &(1 << UDRE0))){};
UDR0 = data;
}
void UART_putstring(uint8_t *data){
while(*data != 0x00){
UART_putchar(*data);
data++;
}
}
//Arduino setup()
void setup(){
pinMode(8, OUTPUT);
UART_init();
sei();
}
//Arduino loop()
void loop(){
UART_putchar(UART_getchar());
}
/*ISR(USART0_RX_vect){
temp = UDR0;
digitalWrite(8, HIGH);
}*/
RX interrupt must be disabled, otherwise Serial interrupt vector is taking place and polled get char can't work as characters are readed by ISR
I am trying to use interrupts to toggle a pin with Arduino Uno. This is what I have so far:
const int outputPin = 12;
void setup() {
pinMode(outputPin, OUTPUT);
// initialize Timer0
noInterrupts(); // disable all interrupts
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 255;
TCCR0B |= (1 << WGM12); // CTC mode
TCCR0B |= (1 << CS12);
TCCR0B |= (1 << CS10); // 1024 prescaler
TIMSK0 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}
ISR(TIMER0_COMPA_vect){
digitalWrite(outputPin,digitalRead(outputPin)^1); //Toggle pin
}
I am using an oscilloscope to read the voltage on the pin and when I change the value of OCR0A there is no change. I am not sure why nothing is changing. I would like to also add that there are no errors.
Thank you for your help!
First, You mix TIMER0 ports and TIMER1 bits constants, use WGM0x, CS0x and so on. You try to set CTC mode like TIMER1. For TIMER0 set bit WGM01 of TCCR0A port:
TCCR0A = 1 << WGM01;
TCCR0B = 1 << CS02 | 1 << CS00;
OCR0A = <Max counter value>;
TIMSK0 |= 1 << OCIE0A;