I am using Arduino_STM32 rogerclark's library.https://github.com/rogerclarkmelbourne/Arduino_STM32 .
Now I want to Develop an In Application Programming(IAP) like a bootloader. Take Code from SD card and Store in Controller flash at 0x8010000 and then jump to that location and run the loaded new application.
the code took from SD and stored into flash successfully done but after jump function called its printing null like this
13:29:04.933 [RX] - Starts............
13:29:07.970 [RX] - 20480 uploaded successfully.
NULNULNULNUL NULNUL
my Main IAP code is
Header file
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
#include <stdint.h>
#include "libmaple/scb.h"
#include "usb_lib.h"
typedef void (*FuncPtr)(void);
#define SCS_BASE ((u32)0xE000E000)
#define NVIC_BASE (SCS_BASE + 0x0100)
#define SCB_BASE (SCS_BASE + 0x0D00)
#define SCS 0xE000E000
#define NVIC (SCS+0x100)
#define SCB (SCS+0xD00)
#define STK (SCS+0x10)
#define SCB_VTOR (SCB+0x08)
#define STK_CTRL (STK+0x00)
#define RCC ((u32)0x40021000)
#define RCC_CR RCC
#define RCC_CFGR (RCC + 0x04)
#define RCC_CIR (RCC + 0x08)
#define USB_LP_IRQ ((u8)0x14)
#define SET_REG(addr,val) do{ *(volatile uint32_t*)(addr)=val;} while(0)
#define GET_REG(addr) (*(vu32*)(addr))
#define pRCC ((rcc_reg_map *) RCC)
typedef struct {
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
bool NVIC_IRQChannelCmd; /* TRUE for enable */
} NVIC_InitTypeDef;
#define RegBase (0x40005C00L)
#define CNTR ((volatile unsigned *)(RegBase + 0x40))
#define _SetCNTR(wRegValue) (*CNTR = (u16)wRegValue)
#define _GetCNTR() ((u16) *CNTR)
#define ISTR ((volatile unsigned *)(RegBase + 0x44))
#define _SetISTR(wRegValue) (*ISTR = (u16)wRegValue)
#define _GetISTR() ((u16) *ISTR)
void setupFLASH();
void usbDsbISR(void);
void nvicInit(NVIC_InitTypeDef *NVIC_InitStruct);
void nvicDisableInterrupts();
void setMspAndJump(u32 usrAddr);
void systemReset(void);
RESULT usbPowerOff(void);
void setupFLASH()
{
/* configure the HSI oscillator */
if ((pRCC->CR & 0x01) == 0x00)
{
u32 rwmVal = pRCC->CR;
rwmVal |= 0x01;
pRCC->CR = rwmVal;
}
/* wait for it to come on */
while ((pRCC->CR & 0x02) == 0x00) {}
}
void usbDsbISR(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = FALSE;
nvicInit(&NVIC_InitStructure);
}
void nvicInit(NVIC_InitTypeDef *NVIC_InitStruct)
{
u32 tmppriority = 0x00;
u32 tmpreg = 0x00;
u32 tmpmask = 0x00;
u32 tmppre = 0;
u32 tmpsub = 0x0F;
scb_reg_map *rSCB = (scb_reg_map *) SCB_BASE;
nvic_reg_map *rNVIC = (nvic_reg_map *) NVIC_BASE;
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700)) >> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
tmpreg = rNVIC->IP[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)];
tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
tmpreg &= ~tmpmask;
tmppriority &= tmpmask;
tmpreg |= tmppriority;
rNVIC->IP[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg;
/* Enable the Selected IRQ Channels --------------------------------------*/
rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
(u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
}
void nvicDisableInterrupts()
{
nvic_reg_map *rNVIC = (nvic_reg_map *) NVIC_BASE;
rNVIC->ICER[0] = 0xFFFFFFFF;
rNVIC->ICER[1] = 0xFFFFFFFF;
rNVIC->ICPR[0] = 0xFFFFFFFF;
rNVIC->ICPR[1] = 0xFFFFFFFF;
SET_REG(STK_CTRL, 0x04); /* disable the systick, which operates separately from nvic */
}
void usbDsbBus(void)
{
// setPin(USB_DISC_BANK,USB_DISC_PIN);
usbPowerOff();
// SET_REG(USB_DISC_CR,
// (GET_REG(USB_DISC_CR) & USB_DISC_CR_MASK) | USB_DISC_CR_OUTPUT);
// resetPin(USB_DISC_BANK, USB_DISC_PIN); /* Pull DP+ down */
// volatile unsigned x = 500000; do { ; }while(--x);
// SET_REG(USB_DISC_CR,
// (GET_REG(USB_DISC_CR) & USB_DISC_CR_MASK) | USB_DISC_CR_INPUT); //Sets the PA12 as floating
input
}
RESULT usbPowerOff(void)
{
#define CNTR_PDWN (0x0002) /* Power DoWN */
#define CNTR_FRES (0x0001) /* Force USB RESet */
_SetCNTR(CNTR_FRES);
_SetISTR(0);
_SetCNTR(CNTR_FRES + CNTR_PDWN);
/* note that all weve done here is powerdown the
usb peripheral. we have no disabled the clocks,
pulled the USB_DISC_PIN pin back up, or reset the
application state machines */
return USB_SUCCESS;
}
void systemReset(void)
{
SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001);
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000);
SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF);
SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF);
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF);
SET_REG(RCC_CIR, 0x00000000); /* disable all RCC interrupts */
}
void setMspAndJump(u32 usrAddr)
{
// Dedicated function with no call to any function (appart the last call)
// This way, there is no manipulation of the stack here, ensuring that GGC
// didn't insert any pop from the SP after having set the MSP.
typedef void (*funcPtr)(void);
u32 jumpAddr = *(vu32 *)(usrAddr + 0x04); /* reset ptr in vector table */
funcPtr usrMain = (funcPtr) jumpAddr;
SET_REG(SCB_VTOR, (vu32) (usrAddr));
asm volatile("msr msp, %0"::"g"(*(volatile u32 *)usrAddr));
usrMain(); /* go! */
}
main code is
#include "core_test.h"
#define CS PB9
File myFile;
char Name[15] = "ASCII.bin";
uint32_t Count = 0;
uint32_t total = 0;
#define FLASH_FLAG_EOP ((uint32_t)0x00000020) /* FLASH End of Operation flag */
#define FLASH_FLAG_PGERR ((uint32_t)0x00000004) /* FLASH Program error flag */
#define FLASH_FLAG_WRPRTERR ((uint32_t)0x00000010) /* FLASH Write protected error flag */
#define myFLASH_APP_ADDR 0x08000000
#define FLASH_APP_ADDR 0x08010000 //The first application start address (stored in FLASH)
#define STM_PAGE_SIZE 2048 //Note: The FLASH page size of STM32F103ZET6 is 2K.
//****************************************************************************************************
// Global variable declaration
char buff[STM_PAGE_SIZE];
int res;
unsigned int br;
void Jump2App(uint32_t Addr)
{
if (((*(uint32_t*)Addr) & 0x2FFE0000) == 0x20000000) //Check if the top address of the stack is legal.
{
// FLASH_Lock();
usbDsbISR(); //Serial1.println("1");
nvicDisableInterrupts(); //Serial1.println("2");
usbDsbBus(); //Serial1.println("3");
// Does nothing, as PC12 is not connected on teh Maple mini according to the schemmatic setPin(GPIOC, 12); // disconnect usb from host. todo, macroize pin
systemReset(); // resets clocks and periphs, not core regs
//Serial1.println("4");
setMspAndJump(Addr);
}
}
void FirmwareUpdate(void)
{
int PageOffest = 0;
int ByteOffest;
if (! IsFileExists(Name)) return;
myFile = SD.open(Name);
while (1)
{
if (Read_data_from_File(buff))
{
FLASH_Unlock();
// FLASH_ClearFlag(((uint16_t)0x00000034));
// FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);
for (ByteOffest = 0; ByteOffest < STM_PAGE_SIZE; ByteOffest += 2)
{
total = total + 2;
FLASH_ProgramHalfWord(FLASH_APP_ADDR + PageOffest + ByteOffest, *(uint16_t*)(buff + ByteOffest));
}
FLASH_Lock();
PageOffest += STM_PAGE_SIZE;
// Serial1.println(PageOffest);
}
else if (myFile.size() <= total) break;
}
myFile.close();
Serial1.println(total);
//myFile.close();
}
void setup()
{
afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY);
Serial1.begin(9600);
if (!SD.begin(CS))
{
Serial1.println("No SD............");
Jump2App(FLASH_APP_ADDR);
}
delay(1000);
Serial1.println("Starts............"); delay(2000);
FirmwareUpdate();
Jump2App(FLASH_APP_ADDR);
while (1);
}
void loop()
{}
bool IsFileExists(char FileName[])
{
if (SD.exists(FileName)) return 1;
else return 0;
}
bool Read_data_from_File(char str[])
{
memset(str, 255, 2048);
uint16_t i = 0;
if (myFile.size() < total)
{
//memset(str, 255, 2048);
// Serial1.println("File Closed");
// Serial1.println(total);
return 0;
}
if (myFile)
{
while (i < 2048)
{
str[i++] = myFile.read();
Count = Count + 1;
if (myFile.size() < Count)
{
//memset(str, 255, 2048);
// Serial1.println("File Closed");
// Serial1.println(Count);
return 1;
}
}
}
else return 0;
}
my user Application code is ASCIItable example code which is given in arduino
before generation this ASCII.bin file
i have changed ROM location address 0x8000000 to 0x8010000 and compiled the file.
Is this process correct,
please help me where I am doing wrong
Related
I am trying to follow a tutorial from youtube on using ROS with Arduino to control motors, and I have connected my L298N with the battery precisely as the video describes and have uploaded sketch 1 with the supporting folder and it loads properly. The Arduino is powered properly via USB, but that connection is not shown in the diagram. When I type the "e" command, I get the proper response of "0 0" and when I do the "o 255 255" it says "OK" and drives properly but upon using "e" to recheck the encoders I am getting the same "0 0". If anyone can spot something wrong with this, I would really appreciate the help in fixing it. Diagram and Code Below
Code:
#define USE_BASE // Enable the base controller code
//#undef USE_BASE // Disable the base controller code
/* Define the motor controller and encoder library you are using */
#ifdef USE_BASE
/* The Pololu VNH5019 dual motor driver shield */
//#define POLOLU_VNH5019
/* The Pololu MC33926 dual motor driver shield */
//#define POLOLU_MC33926
/* The RoboGaia encoder shield */
//#define ROBOGAIA
/* Encoders directly attached to Arduino board */
#define ARDUINO_ENC_COUNTER
/* L298 Motor driver*/
#define L298_MOTOR_DRIVER
#endif
//#define USE_SERVOS // Enable use of PWM servos as defined in servos.h
#undef USE_SERVOS // Disable use of PWM servos
/* Serial port baud rate */
#define BAUDRATE 57600
/* Maximum PWM signal */
#define MAX_PWM 255
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
/* Include definition of serial commands */
#include "commands.h"
/* Sensor functions */
#include "sensors.h"
/* Include servo support if required */
#ifdef USE_SERVOS
#include <Servo.h>
#include "servos.h"
#endif
#ifdef USE_BASE
/* Motor driver function definitions */
#include "motor_driver.h"
/* Encoder driver function definitions */
#include "encoder_driver.h"
/* PID parameters and functions */
#include "diff_controller.h"
/* Run the PID loop at 30 times per second */
#define PID_RATE 30 // Hz
/* Convert the rate into an interval */
const int PID_INTERVAL = 1000 / PID_RATE;
/* Track the next time we make a PID calculation */
unsigned long nextPID = PID_INTERVAL;
/* Stop the robot if it hasn't received a movement command
in this number of milliseconds */
#define AUTO_STOP_INTERVAL 2000
long lastMotorCommand = AUTO_STOP_INTERVAL;
#endif
/* Variable initialization */
// A pair of varibles to help parse serial commands (thanks Fergs)
int arg = 0;
int index = 0;
// Variable to hold an input character
char chr;
// Variable to hold the current single-character command
char cmd;
// Character arrays to hold the first and second arguments
char argv1[16];
char argv2[16];
// The arguments converted to integers
long arg1;
long arg2;
/* Clear the current command parameters */
void resetCommand() {
cmd = NULL;
memset(argv1, 0, sizeof(argv1));
memset(argv2, 0, sizeof(argv2));
arg1 = 0;
arg2 = 0;
arg = 0;
index = 0;
}
/* Run a command. Commands are defined in commands.h */
int runCommand() {
int i = 0;
char *p = argv1;
char *str;
int pid_args[4];
arg1 = atoi(argv1);
arg2 = atoi(argv2);
switch(cmd) {
case GET_BAUDRATE:
Serial.println(BAUDRATE);
break;
case ANALOG_READ:
Serial.println(analogRead(arg1));
break;
case DIGITAL_READ:
Serial.println(digitalRead(arg1));
break;
case ANALOG_WRITE:
analogWrite(arg1, arg2);
Serial.println("OK");
break;
case DIGITAL_WRITE:
if (arg2 == 0) digitalWrite(arg1, LOW);
else if (arg2 == 1) digitalWrite(arg1, HIGH);
Serial.println("OK");
break;
case PIN_MODE:
if (arg2 == 0) pinMode(arg1, INPUT);
else if (arg2 == 1) pinMode(arg1, OUTPUT);
Serial.println("OK");
break;
case PING:
Serial.println(Ping(arg1));
break;
#ifdef USE_SERVOS
case SERVO_WRITE:
servos[arg1].setTargetPosition(arg2);
Serial.println("OK");
break;
case SERVO_READ:
Serial.println(servos[arg1].getServo().read());
break;
#endif
#ifdef USE_BASE
case READ_ENCODERS:
Serial.print(readEncoder(LEFT));
Serial.print(" ");
Serial.println(readEncoder(RIGHT));
break;
case RESET_ENCODERS:
resetEncoders();
resetPID();
Serial.println("OK");
break;
case MOTOR_SPEEDS:
/* Reset the auto stop timer */
lastMotorCommand = millis();
if (arg1 == 0 && arg2 == 0) {
setMotorSpeeds(0, 0);
resetPID();
moving = 0;
}
else moving = 1;
leftPID.TargetTicksPerFrame = arg1;
rightPID.TargetTicksPerFrame = arg2;
Serial.println("OK");
break;
case MOTOR_RAW_PWM:
/* Reset the auto stop timer */
lastMotorCommand = millis();
resetPID();
moving = 0; // Sneaky way to temporarily disable the PID
setMotorSpeeds(arg1, arg2);
Serial.println("OK");
break;
case UPDATE_PID:
while ((str = strtok_r(p, ":", &p)) != '\0') {
pid_args[i] = atoi(str);
i++;
}
Kp = pid_args[0];
Kd = pid_args[1];
Ki = pid_args[2];
Ko = pid_args[3];
Serial.println("OK");
break;
#endif
default:
Serial.println("Invalid Command");
break;
}
}
/* Setup function--runs once at startup. */
void setup() {
Serial.begin(BAUDRATE);
// Initialize the motor controller if used */
#ifdef USE_BASE
#ifdef ARDUINO_ENC_COUNTER
//set as inputs
DDRD &= ~(1<<LEFT_ENC_PIN_A);
DDRD &= ~(1<<LEFT_ENC_PIN_B);
DDRC &= ~(1<<RIGHT_ENC_PIN_A);
DDRC &= ~(1<<RIGHT_ENC_PIN_B);
//enable pull up resistors
PORTD |= (1<<LEFT_ENC_PIN_A);
PORTD |= (1<<LEFT_ENC_PIN_B);
PORTC |= (1<<RIGHT_ENC_PIN_A);
PORTC |= (1<<RIGHT_ENC_PIN_B);
// tell pin change mask to listen to left encoder pins
PCMSK2 |= (1 << LEFT_ENC_PIN_A)|(1 << LEFT_ENC_PIN_B);
// tell pin change mask to listen to right encoder pins
PCMSK1 |= (1 << RIGHT_ENC_PIN_A)|(1 << RIGHT_ENC_PIN_B);
// enable PCINT1 and PCINT2 interrupt in the general interrupt mask
PCICR |= (1 << PCIE1) | (1 << PCIE2);
#endif
initMotorController();
resetPID();
#endif
/* Attach servos if used */
#ifdef USE_SERVOS
int i;
for (i = 0; i < N_SERVOS; i++) {
servos[i].initServo(
servoPins[i],
stepDelay[i],
servoInitPosition[i]);
}
#endif
}
/* Enter the main loop. Read and parse input from the serial port
and run any valid commands. Run a PID calculation at the target
interval and check for auto-stop conditions.
*/
void loop() {
while (Serial.available() > 0) {
// Read the next character
chr = Serial.read();
// Terminate a command with a CR
if (chr == 13) {
if (arg == 1) argv1[index] = NULL;
else if (arg == 2) argv2[index] = NULL;
runCommand();
resetCommand();
}
// Use spaces to delimit parts of the command
else if (chr == ' ') {
// Step through the arguments
if (arg == 0) arg = 1;
else if (arg == 1) {
argv1[index] = NULL;
arg = 2;
index = 0;
}
continue;
}
else {
if (arg == 0) {
// The first arg is the single-letter command
cmd = chr;
}
else if (arg == 1) {
// Subsequent arguments can be more than one character
argv1[index] = chr;
index++;
}
else if (arg == 2) {
argv2[index] = chr;
index++;
}
}
}
// If we are using base control, run a PID calculation at the appropriate intervals
#ifdef USE_BASE
if (millis() > nextPID) {
updatePID();
nextPID += PID_INTERVAL;
}
// Check to see if we have exceeded the auto-stop interval
if ((millis() - lastMotorCommand) > AUTO_STOP_INTERVAL) {;
setMotorSpeeds(0, 0);
moving = 0;
}
#endif
// Sweep servos
#ifdef USE_SERVOS
int i;
for (i = 0; i < N_SERVOS; i++) {
servos[i].doSweep();
}
#endif
}
Encoder Pin Designations:
/* *************************************************************
Encoder driver function definitions - by James Nugen
************************************************************ */
#ifdef ARDUINO_ENC_COUNTER
//below can be changed, but should be PORTD pins;
//otherwise additional changes in the code are required
#define LEFT_ENC_PIN_A PD2 //pin 2
#define LEFT_ENC_PIN_B PD3 //pin 3
//below can be changed, but should be PORTC pins
#define RIGHT_ENC_PIN_A PC4 //pin A4
#define RIGHT_ENC_PIN_B PC5 //pin A5
#endif
long readEncoder(int i);
void resetEncoder(int i);
void resetEncoders();
Encoder Driver:
/* *************************************************************
Encoder definitions
Add an "#ifdef" block to this file to include support for
a particular encoder board or library. Then add the appropriate
#define near the top of the main ROSArduinoBridge.ino file.
************************************************************ */
#ifdef USE_BASE
#ifdef ROBOGAIA
/* The Robogaia Mega Encoder shield */
#include "MegaEncoderCounter.h"
/* Create the encoder shield object */
MegaEncoderCounter encoders = MegaEncoderCounter(4); // Initializes the Mega Encoder Counter in the 4X Count mode
/* Wrap the encoder reading function */
long readEncoder(int i) {
if (i == LEFT) return encoders.YAxisGetCount();
else return encoders.XAxisGetCount();
}
/* Wrap the encoder reset function */
void resetEncoder(int i) {
if (i == LEFT) return encoders.YAxisReset();
else return encoders.XAxisReset();
}
#elif defined(ARDUINO_ENC_COUNTER)
volatile long left_enc_pos = 0L;
volatile long right_enc_pos = 0L;
static const int8_t ENC_STATES [] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0}; //encoder lookup table
/* Interrupt routine for LEFT encoder, taking care of actual counting */
ISR (PCINT2_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PIND & (3 << 2)) >> 2; //read the current state into lowest 2 bits
left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Interrupt routine for RIGHT encoder, taking care of actual counting */
ISR (PCINT1_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINC & (3 << 4)) >> 4; //read the current state into lowest 2 bits
right_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Wrap the encoder reading function */
long readEncoder(int i) {
if (i == LEFT) return left_enc_pos;
else return right_enc_pos;
}
/* Wrap the encoder reset function */
void resetEncoder(int i) {
if (i == LEFT){
left_enc_pos=0L;
return;
} else {
right_enc_pos=0L;
return;
}
}
#else
#error A encoder driver must be selected!
#endif
/* Wrap the encoder reset function */
void resetEncoders() {
resetEncoder(LEFT);
resetEncoder(RIGHT);
}
#endif
I think if you use a Mega instead of an Uno, the pin ports are different.
So change the port from PD4 to PE4 and PD3 to PE5. Also, change PC4 to PF4 and PC5 to PF5.
In the Encoder.ino, you also have to change the ports accordingly.
Encoder.h:
#define LEFT_ENC_PIN_A PE4 //pin 2
#define LEFT_ENC_PIN_B PE5 //pin 3
//below can be changed, but should be PORTC pins
#define RIGHT_ENC_PIN_A PF5 //pin A4
#define RIGHT_ENC_PIN_B PF5 //pin A5
Encoder.ino:
/* Interrupt routine for LEFT encoder, taking care of actual counting */
ISR (PCINT2_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINE & (3 << 2)) >> 2; //read the current state into lowest 2 bits
left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
/* Interrupt routine for RIGHT encoder, taking care of actual counting */
ISR (PCINT1_vect){
static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PINF & (3 << 4)) >> 4; //read the current state into lowest 2 bits
right_enc_pos += ENC_STATES[(enc_last & 0x0f)];
}
I am trying to interface an LCD using I2C but can't quite understand how to do it.
I found this example
Here's the code:
i2c.h:
/* File: I2C_LCD.h */
#define _XTAL_FREQ 16000000
#define I2C_BaudRate 100000
#define SCL_D TRISC3
#define SDA_D TRISC4
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#define LCD_FIRST_ROW 0x80
#define LCD_SECOND_ROW 0xC0
#define LCD_THIRD_ROW 0x94
#define LCD_FOURTH_ROW 0xD4
#define LCD_CLEAR 0x01
#define LCD_RETURN_HOME 0x02
#define LCD_ENTRY_MODE_SET 0x04
#define LCD_CURSOR_OFF 0x0C
#define LCD_UNDERLINE_ON 0x0E
#define LCD_BLINK_CURSOR_ON 0x0F
#define LCD_MOVE_CURSOR_LEFT 0x10
#define LCD_MOVE_CURSOR_RIGHT 0x14
#define LCD_TURN_ON 0x0C
#define LCD_TURN_OFF 0x08
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1E
#define LCD_TYPE 2 // 0 -> 5x7 | 1 -> 5x10 | 2 -> 2 lines
//-----------[ Functions' Prototypes ]--------------
//---[ I2C Routines ]---
void I2C__Init();
void I2C__Wait();
void I2C__Start();
void I2C__RepeatedStart();
void I2C__Stop();
void I2C_ACK();
void I2C_NACK();
unsigned char I2C__Write(unsigned char data);
unsigned char I2C_Read_Byte(void);
//---[ LCD Routines ]---
void LCD_Init(unsigned char I2C_Add);
void IO_Expander_Write(unsigned char Data);
void LCD_Write_4Bit(unsigned char Nibble);
void LCD_CMD(unsigned char CMD);
void LCD_Set_Cursor(unsigned char ROW, unsigned char COL);
void LCD_Write_Char(char);
void LCD_Write_String(char*);
void Backlight();
void noBacklight();
void LCD_SR();
void LCD_SL();
void LCD_Clear();
I2c.c
#include <xc.h>
#include "I2C.h"
unsigned char RS, i2c_add, BackLight_State = LCD_BACKLIGHT;
//---------------[ I2C Routines ]-------------------
//--------------------------------------------------
void I2C__Init()
{
SSPCON = 0x28;
SSPCON2 = 0x00;
SSPSTAT = 0x00;
SSPADD = ((_XTAL_FREQ/4)/I2C_BaudRate) - 1;
SCL_D = 1;
SDA_D = 1;
}
void I2C__Wait()
{
while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}
void I2C__Start()
{
I2C__Wait();
SEN = 1;
}
void I2C__RepeatedStart()
{
I2C__Wait();
RSEN = 1;
}
void I2C__Stop()
{
I2C__Wait();
PEN = 1;
}
void I2C_ACK(void)
{
ACKDT = 0; // 0 -> ACK
I2C__Wait();
ACKEN = 1; // Send ACK
}
void I2C_NACK(void)
{
ACKDT = 1; // 1 -> NACK
I2C__Wait();
ACKEN = 1; // Send NACK
}
unsigned char I2C__Write(unsigned char data)
{
I2C__Wait();
SSPBUF = data;
while(!SSPIF); // Wait Until Completion
SSPIF = 0;
return ACKSTAT;
}
unsigned char I2C_Read_Byte(void)
{
//---[ Receive & Return A Byte ]---
I2C__Wait();
RCEN = 1; // Enable & Start Reception
while(!SSPIF); // Wait Until Completion
SSPIF = 0; // Clear The Interrupt Flag Bit
I2C__Wait();
return SSPBUF; // Return The Received Byte
}
//======================================================
//---------------[ LCD Routines ]----------------
//------------------------------------------------------
void LCD_Init(unsigned char I2C_Add)
{
i2c_add = I2C_Add;
IO_Expander_Write(0x00);
__delay_ms(30);
LCD_CMD(0x03);
__delay_ms(5);
LCD_CMD(0x03);
__delay_ms(5);
LCD_CMD(0x03);
__delay_ms(5);
LCD_CMD(LCD_RETURN_HOME);
__delay_ms(5);
LCD_CMD(0x20 | (LCD_TYPE << 2));
__delay_ms(50);
LCD_CMD(LCD_TURN_ON);
__delay_ms(50);
LCD_CMD(LCD_CLEAR);
__delay_ms(50);
LCD_CMD(LCD_ENTRY_MODE_SET | LCD_RETURN_HOME);
__delay_ms(50);
}
void IO_Expander_Write(unsigned char Data)
{
I2C__Start();
I2C__Write(i2c_add);
I2C__Write(Data | BackLight_State);
I2C__Stop();
}
void LCD_Write_4Bit(unsigned char Nibble)
{
// Get The RS Value To LSB OF Data
Nibble |= RS;
IO_Expander_Write(Nibble | 0x04);
IO_Expander_Write(Nibble & 0xFB);
__delay_us(50);
}
void LCD_CMD(unsigned char CMD)
{
RS = 0; // Command Register Select
LCD_Write_4Bit(CMD & 0xF0);
LCD_Write_4Bit((CMD << 4) & 0xF0);
}
void LCD_Write_Char(char Data)
{
RS = 1; // Data Register Select
LCD_Write_4Bit(Data & 0xF0);
LCD_Write_4Bit((Data << 4) & 0xF0);
}
void LCD_Write_String(char* Str)
{
for(int i=0; Str[i]!='\0'; i++)
LCD_Write_Char(Str[i]);
}
void LCD_Set_Cursor(unsigned char ROW, unsigned char COL)
{
switch(ROW)
{
case 2:
LCD_CMD(0xC0 + COL-1);
break;
case 3:
LCD_CMD(0x94 + COL-1);
break;
case 4:
LCD_CMD(0xD4 + COL-1);
break;
// Case 1
default:
LCD_CMD(0x80 + COL-1);
}
}
void Backlight()
{
BackLight_State = LCD_BACKLIGHT;
IO_Expander_Write(0);
}
void noBacklight()
{
BackLight_State = LCD_NOBACKLIGHT;
IO_Expander_Write(0);
}
void LCD_SL()
{
LCD_CMD(0x18);
__delay_us(40);
}
void LCD_SR()
{
LCD_CMD(0x1C);
__delay_us(40);
}
void LCD_Clear()
{
LCD_CMD(0x01);
__delay_us(40);
}
main.c:
#include "I2C.h"
void main(void) {
I2C__Init();
LCD_Init(0x4E); // Initialize LCD module with I2C address = 0x4E
LCD_Set_Cursor(1, 1);
LCD_Write_String(" Welcome To ");
LCD_Set_Cursor(2, 1);
LCD_Write_String(" MicroDigiSoft ");
delay_ms(2500);
while(1)
{
}
return;
}
But I get these Errors:
Screenshot of Error
Screenshot of Error
I am using MikroC and one thing to note is that I have included the system libraries Lcd and Lcd Constants.
How can I fix these errors, and are there any examples of interfacing LCD I2C with microcontrollers apart from this?
You must import the I2C system libray in the the MikroC Library Manager, at the right panel. See the attached image:
I am trying to set the timer after which the audio will automatically played once but it is not playing anything just a noise but when i run the audio program separately it work perfectly good
This is my code please help me out where i am doing wrong.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <TMRpcm.h>
#include <SPI.h>
int timer1_counter;
#define SD_ChipSelectPin 4
TMRpcm tmrpcm;
unsigned long time_now = 0;
LiquidCrystal_I2C lcd(0x27, 16, 2);
const byte ledPin = 13;
const byte interruptPin1 = 2;
const byte interruptPin2 = 3;
int counter2 = 0;
volatile byte state = LOW;
int count = 0;
int limit = 0;
bool TimerFlag = false;
int deviceTime = 0;
int set = 5;
bool soundplayflag = false;
void setup()
{
lcd.begin();
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(interruptPin1, INPUT_PULLUP);
pinMode(interruptPin2, INPUT_PULLUP);
pinMode(set, INPUT_PULLUP);
lcd.backlight();
lcd.setCursor(1,0);
lcd.print("Please Select:");
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 31250; // compare match register 16MHz/256/2Hz
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
// initialize timer1
}
ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
if (soundplayflag == true)
{
counter2 = counter2+1;
Serial.println(counter2/2);
}
}
void loop()
{
//unsigned long currentMillis = millis();
int up = digitalRead(interruptPin1);
int down = digitalRead(interruptPin2);
int setbutton = digitalRead(set);
delay(230);
if (up == 0)
{
Serial.println("Entering up");
count++;
if (count >= 0) {
lcdprint(count);
}
}
else if (down == 0)
{
Serial.println("Entering down");
count--;
if (count >= 0) {
lcdprint(count);
}
}
else if (setbutton == 0)
{
Serial.println("Entering set");
soundplayflag=true;
deviceTime = count;
}
if (deviceTime > 0)
{
if (deviceTime == counter2)
{
soundplayflag=false;
Serial.println("Hello world");
PlaySound();
counter2 = 0;
}
}
}
int lcdprint(int a)
{
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Please Select:");
lcd.setCursor (7,1);
lcd.print(a);
Serial.println(a);
lcd.setCursor (10,1);
lcd.print("Min");
}// end of lcdprint(int a)
void PlaySound()
{
for (int i = 0; i < 10; i++)
{
tmrpcm.setVolume(5);
tmrpcm.play("3.wav");
delay(1000);
}// end of for loop
}// end of void PlaySound()
my expected output is it should play the sound when i set the time
It seems TMRpcm uses Timer1, which conflicts with your TIMER1_COMPA_vect. That would explain why it's working if you run nothing else.
Maybe try to use #define USE_TIMER2?
I have multiple variable length strings which do not exceed 32 bytes each which need to be sent via I2C between 2 Arduino Nanos. I use # to terminate each string. I can successfully send and receive the first string, but for the life of me I can't figure out how to send the succeeding strings. The samples I am testing with look like this:
String answer = "12345,123.4,50.6,12345#";
String answerV = "4.10,4.15,4.13,4.05,4.18,0#";
Master Code
#include <Wire.h>
int esc = 0;
int throttle = 80;
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("I2C Master ready!");
esc = throttle * 100 / 180;
}
void loop() {
delay(500);
Serial.println("Receive data");
Wire.requestFrom(9,32);
String response = "";
Serial.println(Wire.available());
while (Wire.available())
{
char b = Wire.read();
response += b;
}
String dataString = response;
int hashIndex = dataString.indexOf('#');
String SportData = dataString.substring(0, hashIndex);
Serial.println(SportData);
String SDdata = String (esc) + "," + String(SportData);
Serial.println(SDdata);
}
Slave Code
#include <Wire.h>
byte ANSWERSIZE= 22;
String answer = "12345,123.4,50.6,12345#";
String answerV = "4.10,4.15,4.13,4.05,4.18,0#";
void setup() {
Wire.begin(9);
Wire.onRequest(requestEvent); // data request from Master
Serial.begin(115200);
Serial.println("I2C Slave ready!");
ANSWERSIZE = answer.length();
}
void requestEvent() {
byte response[ANSWERSIZE];
for (byte i=0;i<ANSWERSIZE;i++)
{
response[i] = (byte)answer.charAt(i);
}
Wire.write(response,sizeof(response));
}
void loop() {
delay(50);
}
Can someone please show me how this can be done?
A simple idea is to keep track of the number of times requestEvent() is called, and use that to decide what to send back to the master.
Here is the code (n.b. I took the liberty to optimise it a bit):
Master:
#include <Wire.h>
/**
* globals
*/
int esc = 0;
int throttle = 80;
char i2c_buffer[33];
/**
* setup & loop
*/
void setup()
{
Serial.begin(115200);
Wire.begin();
esc = throttle * 100 / 180;
i2c_buffer[32] = '\0';
Serial.println("I2C Master ready!");
}
void loop()
{
delay(500);
Wire.requestFrom(9, 32);
for (byte i = 0; i < 32 && Wire.available(); ++i)
{
i2c_buffer[i] = Wire.read();
if (i2c_buffer[i] == '#') {
i2c_buffer[i] = '\0';
break;
}
}
Serial.print(esc);
Serial.print(',');
Serial.println(i2c_buffer);
}
Slave:
#include <Wire.h>
/**
* globals
*/
const byte DATA_SIZE = 2;
String data[DATA_SIZE] = {
"12345,123.4,50.6,12345#",
"4.10,4.15,4.13,4.05,4.18,0#"
};
/**
* setup & loop
*/
void setup()
{
Serial.begin(115200);
Wire.begin(9);
Wire.onRequest(requestEvent); // data request from Master
Serial.println("I2C Slave ready!");
}
void loop()
{
delay(50);
}
/**
* help functions
*/
void requestEvent()
{
static byte req_number = 0;
Wire.write(reinterpret_cast<const unsigned char*>(data[req_number].c_str()),
data[req_number].length());
req_number = (req_number + 1) % DATA_SIZE;
}
Note: I don't have two Arduino devices, so I could not test this code. If you spot some bugs, report back and I'll fix them.
I am facing a problem with atmega2560 serial outport port. When I connect AVRISPmkII programmer to atmega2560, all serial port gives output data at specified baud rate but when I disconnect programmer, there is no output but 1 second led blinks. I don't think that this is the code proble!m. I have not tried it with other programmer as that is all I have. The code is very simple anyway - blink led at 1 second and give output through RS232 port.
Voltage at reset pin is 5V and at sck is about 1.19V whether or not programmer is connected.
What is the problem here ?
The figure shows ISP and serial port circuits.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <string.h>
void USART0_init(void) /*************** USART 0 ***********************/
{
UCSR0A = 0x00;
UCSR0B = 0b00011000;
UCSR0C = 0b00000110;
UBRR0H = 0x00;
UBRR0L = 103; //baud rate: 9600, right - rx, tx, gnd - left
}
void USART0_putc(char data)
{
while(!(UCSR0A&0x20));
UDR0=data;
}
void USART0_puts(char* str){
while(*str) {USART0_putc(*str++);}
}
void USART1_init(void) /*************** USART 1 ***********************/
{
UCSR1A = 0x00;
UCSR1B = 0b10011000;
UCSR1C = 0b00000110;
UBRR1H = 0x00;
UBRR1L = 103; //baudrate: 9600
}
void USART1_putc(char data)
{
while(!(UCSR1A&0x20));
UDR1=data;
}
void USART1_puts(char* str){
while(*str) {USART1_putc(*str++);}
}
char t = 0;
char rx_buf1[50];
ISR(USART1_RX_vect)
{
cli();
t = UDR1;
rx_buf1[cnt1++] = t;
if (t == 0x0a){ // detect EOL \n FOR NOW
rx_buf1[cnt1] = '\0';
sprintf(out_buf1, "\r\nS1, ");
strcat(out_buf1, (const char*)rx_buf1);
sprintf(out_buf1, ", /");
USART0_puts(out_buf1);
cnt1 = 0;
rx_complete1 = 1;
}
if (cnt1 >= 50){
cnt1 = 0;
}
sei();
}
void timer_init(void)
{
cli();
TCCR1B = (1<<WGM12); //CTC mode
OCR1A = 1561; //100 ms
TIMSK1 |= (1<<OCIE1A);
TCCR1B |= (1<<CS12)|(0<<CS11)|(1<<CS10);
}
void dev_init(void)
{
DDRA = 0x0F;
PORTA = 0x00;
timer_init();
stdout = &uart0_str;
stderr = &uart1_str;
USART0_init();
USART1_init();
sei();
}
int main(void)
{
dev_init();
while(1)
{
process();
}
return 0;
}
volatile unsigned char tick_100ms;
char out_buf[100];
float speed = 4.3;
void process(void){
static unsigned char lc=1;
static uint8_t tick_cnt = 0;
if (tick_100ms){
tick_100ms = 0;
tick_cnt++;
if (tick_cnt == 10){
tick_cnt = 0;
PORTA = ~lc; /* this code is for blinking 4 LEDS */
lc = lc*2; /* very 1 seconds alternately*/
if (lc >8) lc = 1;
sprintf(out_buf, "S1, speed: %05.2f/\r\n", (double)speed);
USART0_puts(out_buf);
USART1_puts(out_buf);
}
}
}
I gave posted my code below.
The uart 1 interrupt code is not needed because there is no incoming data. Disabling them made no difference.