Programming e-ink display on atmega32 without arduino - c

i've bought eink 1,54 display module from waveshare, i want to program atmega32 and design a gui with keys on this eink. I wrote a simple code using spi in eclipse:
#include <avr/io.h>
#include <util/delay.h>
void Inicjacja_spi()
{
DDRB = ( 1 << PB5 ) | ( 1 << PB7 ) | ( 1 << PB4 );
SPCR = ( 1 << SPE ) | ( 1 << MSTR ) | (1<<SPI2X) |( 1 << SPR1 ) | ( 1 << SPR0 );
}
void Wyslij_spi(unsigned char bajt)
{
SPDR = bajt;
while( ! bit_is_set( SPSR, SPIF ) );
}
int main()
{
unsigned char bajt[] = {0x04,0x20,0x21,0x22,0x25,0x26,0x27};
Inicjacja_spi();
for(int i=0; i<8; i++)
Wyslij_spi(bajt[i]);
while(1)
{
}
}
I have read about how to send commands through spi to this eink but it didnt work. Do i have to write complicated libraries to send some data into display? I guess it should work using simple commands, but maybe i'am doing somethin wrong. If someone can tell me how can i write simple commands into this thing because i dont understand those documentations. Simple working example should help me.

I'd start with the display manufacturers documentation first.
Typically these devices need specific drivers and the manufacturer supplies these along with some example code.
The displays themselves normally require some driver hardware, is this included in or with your display module?
I'm sorry but as you don't give any information regarding the display other than where you bought it from and its size I can't be more specific.
edit
Just had a very quick scan through and see that there's a link to a library written to drive these using SPI - Library source on GIT hub
You may be able to adapt it, or glean something useful from the source code.

Related

Embedded system: MSP430g2553 IAR programming ports/pins BASIC Input / Output syntax

To put it simply : How do I define and use ports / pins correctly in IAR EW with MSP430g2553?
Ill use example to clarify what I do not understand.
I have a simple state machine with 3 states. I want to program 3 pins for input and 2 pins for output.
Then, depending on inputs I manage state.
First, is this correct way of defining inputs / outputs ?
P1DIR |= BIT0 + BIT1; //pins 1.0 and 1.1 output
P1DIR &= ~BIT2 + BIT3 + BIT4; // pins 1.2 , 1.3, 1.4 input
The above seems to me fairly straightforward to use, however, bigger question is how do I reference input pins in code ? And how do I set output based on input?
To further my problem, here is my starting code for this state machine and I've put in pseudocode where I dont understand how to write syntax. Would be of great help if anyone could fill in the pseudocode and commentate a bit. I've looked many tutorials but I dont seem to get this simple thing from them.
# include "msp430g2553.h"
# include "stdio.h"
# include "math.h"
#define START 1
#define LEFT_ON 2
#define RIGHT_ON 3
char STATE;
main ()
{
P1DIR |= BIT0 + BIT1; //port 1.0 and 1.1 output
P1DIR &= ~BIT2 + BIT3 + BIT4; // port 1.2 , 1.3, 1.4 input
WDTCTL = WDTPW + WDTHOLD;
STATE =START;
while(1)
{
//STATE = START;
switch (STATE)
{
case START:
{
// Starting state I want both outputs to be set 1, I dont know how
set p1.0 to 1
set p1.1 to 1
puts("START");
//check inputs to switch state
if (1.2 == 1 & 1.3==0 & 1.4==0) {
STATE = RIGHT_ON;
} else if (1.2 == 0 & 1.3==0 & 1.4==1)) {
STATE = LEFT_ON;
}
break;
}
case LEFT_ON:
{
// Here I wish to to put 1.0 output to 1 and 1.1 output to 0
p1.0 set to 1
p1.1 set to 0
// now check if 1.3 is 1
if (1.3 == 1) {
STATE = START;
}
break;
}
case RIGHT_ON:
{
// Here I wish to to put 1.0 output to 0 and 1.1 output to 1
p1.0 set to 0
p1.1 set to 1
// now check if 1.3 is 1
if (1.3 == 1) {
STATE = START;
}
break;
}
}//end of Switch
}// end of while
}// end of main
First, is this correct way of defining inputs / outputs ?
I assume P1DIR is the correct data direction register (I don't know this particular MCU in detail), but apart from that: no, it isn't correct. First of all, use bitwise OR | not addition. They give the same result but + makes the code look strange and a bit harder to read. The average C programming book will tell you to do:
P1DIR |= BIT0 | BIT1;
Note that P1DIR |= ... will leave all pins currently set as output as they are. That may or may not be what you want.
To set a port pin active then simply do the same, SOME_PORT_REGISTER |= PIN_MASK;. Similarly, you can toggle a single pin with ^= which is bitwise XOR. Or set it to zero with &= ~(mask).
P1DIR &= ~BIT2 + BIT3 + BIT4; is wrong, ~ is a unary operator that only applies to one operand. Corrected code:
P1DIR &= ~(BIT2 | BIT3 | BIT4);
I've looked many tutorials
Most tutorials on the web are unfortunately quite bad. Start by reading a decent C programming book before anything else. Once you've learnt the basics of C, you can go look for tutorials.
For example this article about register access I wrote here, it assumed that the reader already knows C: How to access a hardware register from firmware?
As for full beginner tutorials, I think this one has better quality than most: Embedded Software in C for an ARM Cortex M, Jonathan W. Valvano and Ramesh Yerraballi. (It's Cortex M not MSP430 but the principles are very similar no matter MCU. The same author also has an older tutorial that used NXP HSC12 examples, which is another 16 bitter even more similar to MSP430.)

Arduino servo library conflict

In my code I use only LiquidCrystal library and Servo library. When I try to compile the code following error appears
Servo/Servo.cpp.o: In function `Servo::attached()':
/usr/share/arduino/libraries/Servo/Servo.cpp:336: multiple definition of `__vector_42'
robot_v2.cpp.o:/usr/share/arduino/robot_v2.ino:662: first defined here
/usr/lib/gcc/avr/5.4.0/../../../avr/bin/ld: Disabling relaxation: it will not work with multiple definitions
Servo/Servo.cpp.o: In function `Servo::attached()':
/usr/share/arduino/libraries/Servo/Servo.cpp:336: multiple definition of `__vector_47'
robot_v2.cpp.o:/usr/share/arduino/robot_v2.ino:662: first defined here
collect2: error: ld returned 1 exit status
Apart from above mentioned libraries, I use a 16 bit timer as follows.
DDRC |= B01010101;
......
cli();
TCCR4A = 0;
TCCR4B = 0;
TCCR5A = 0;
TCCR5B = 0;
OCR4A = l_target;
OCR5A = l_target;
TCCR4B = _BV(WGM42) | _BV(CS41);
TCCR5B = _BV(WGM52) | _BV(CS51);
TIMSK4 |= (1 << OCIE4A);
TIMSK5 |= (1 << OCIE5A);
sei();
Let me know what I'm doing wrong and how to fix this issue? Are there any other libraries than the standard Servo library for arduino? I'm using Arduino Mega board.
Here are the ISRs.
ISR(TIMER4_COMPA_vect)
{
if (OCR4A != l_target) {
OCR4A = l_target;
}
PORTC ^= B00000001;
}
ISR(TIMER5_COMPA_vect)
{
if (OCR5A != r_target) {
OCR5A = r_target;
}
PORTC ^= B00010000;
}
The servo library allocates timers only as needed. Each timer supports up to 12 servos so on the Mega, 1 to 12 servos use timer5, 13 to 24 will also use timer1 and so on. The allocation order is defined in the file ServoTimers.h as follows: timer5, timer1, timer3, timer4
Assuming you are not using more than 24 servos, timers 3 and 4 are available. If you change all references to timer 5 (TCCR5x, OCR5x, TIMSK5) to timer 3 TCCR3x, OCR3x, TIMSK3) you should not have the conflict.
I found the related code from Servo library. According to that it uses 1,3,4 and 5 timers. So, I cannot use them for any other purpose. I will have to use Timer 2 or any other solution. I'm answering my own question as a reference for any one else who faces similar situation.
// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4

How can I use an older version's CCS header file?

I am trying to include "msp.h" in a CCS v9 project in order to run code in a book I am reading. Here's an example code snippet:
* This program toggles green LED for 0.5 second ON and 0.5 second OFF.
* The green LED is connected to P2.1.
* The LEDs are high active (a '1' turns ON the LED).
*
* Tested with Keil 5.20 and MSP432 Device Family Pack V2.2.0
* on XMS432P401R Rev C.
*/
#include "msp.h"
void delayMs(int n);
int main(void) {
P2->SEL1 &= ~2; /* configure P2.1 as simple I/O */
P2->SEL0 &= ~2;
P2->DIR |= 2; /* P2.1 set as output pin */
while (1) {
P2->OUT |= 2; /* turn on P2.1 green LED */
delayMs(500);
P2->OUT &= ~2; /* turn off P2.1 green LED */
delayMs(500);
}
}
/* delay milliseconds when system clock is at 3 MHz for Rev C MCU */
void delayMs(int n) {
int i, j;
for (j = 0; j < n; j++)
for (i = 750; i > 0; i--); /* Delay 1 ms*/
}
It appears that it needs the msp.h include file to run, but I haven't been able to find the specific header file anywhere in the resource explorer when searching through the msp432 libraries. Any info on how to get this to compile would be great!
Thank you!
You could throw it into the CCS cloud editor likely. Make a new project for your device and copy and paste the code there. It's generally pretty proficient at finding headers.
The basic cycle for stuff like this on the local editor is:
Make sure the development files for the device is installed
Figure out where those files are hiding
Dig through files until you find the header
Go into properties of your project and under compiler options add the folder
What may also help is to make sure you have the MSP432 stuff installed, import it's blinky led example project and see what it's include options are. Or even just modify that newly imported project with this code.
Sorry this isn't a step by step. I'm not on my computer with CCS right now.

Problem with USB CDC settings and libraries for STM32F4

I'm working in an embedded aplication for STM32F401RBT6 and I'm trying to establish a connection with the PC (Windows 10) but the device is not recognized by the system. The code that I generated by STMCubeMX and debugged by Atollic not works. I saw and try reproduce several examples, but anything works. In the code, I have all libraries that i think necessary.
I'm have this archives generated by STMCubeMX for the CDC comunication, but I'm newbie and I don't know what I have to modify on the code for the USB be recognized by the system. Someone can help me?
Beside the point from Soup ( the failing malloc caused by a heap that is only 0x200 by default) some Windows version have a problem with the line coding in the example.
In the usbd_cdc_if.c you should add:
/* USER CODE BEGIN PRIVATE_VARIABLES */
USBD_CDC_LineCodingTypeDef LineCoding =
{
115200, /* baud rate*/
0x00, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* nb. of bits 8*/
};
And a little bit below
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
.
.
.
case CDC_SET_LINE_CODING:
LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
(pbuf[2] << 16) | (pbuf[3] << 24));
LineCoding.format = pbuf[4];
LineCoding.paritytype = pbuf[5];
LineCoding.datatype = pbuf[6];
break;
case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t)(LineCoding.bitrate);
pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8);
pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16);
pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24);
pbuf[4] = LineCoding.format;
pbuf[5] = LineCoding.paritytype;
pbuf[6] = LineCoding.datatype;
break;
So the host won't get undefined data if he tries to set the line coding.
Inside USBD_CDC_Init(..) function there is a malloc function which allocates about 540 Bytes memory on the Heap.
This was not taken into account from CubeMX when code generated .
So , at least you must define the Heap size taking into account theese extra Bytes, to have the USB CDC port working.

Writing Device Drivers for Microcontrollers, where to define IO Port pins?

I always seem to encounter this dilemma when writing low level code for MCU's.
I never know where to declare pin definitions so as to make the code as reusable as possible.
In this case Im writing a driver to interface an 8051 to a MCP4922 12bit serial DAC.
Im unsure how/where I should declare the pin definitions for The CS(chip select) and LDAC(data latch) for the DAC. At the moment there declared in the header file for the driver.
Iv done a lot of research trying to figure out the best approach but havent really found anything.
Im basically want to know what the best practices... if there are some books worth reading or online information, examples etc, any recommendations would be welcome.
Just a snippet of the driver so you get the idea
/**
#brief This function is used to write a 16bit data word to DAC B -12 data bit plus 4 configuration bits
#param dac_data A 12bit word
#param ip_buf_unbuf_select Input Buffered/unbuffered select bit. Buffered = 1; Unbuffered = 0
#param gain_select Output Gain Selection bit. 1 = 1x (VOUT = VREF * D/4096). 0 =2x (VOUT = 2 * VREF * D/4096)
*/
void MCP4922_DAC_B_TX_word(unsigned short int dac_data, bit ip_buf_unbuf_select, bit gain_select)
{
unsigned char low_byte=0, high_byte=0;
CS = 0; /**Select the chip*/
high_byte |= ((0x01 << 7) | (0x01 << 4)); /**Set bit to select DAC A and Set SHDN bit high for DAC A active operation*/
if(ip_buf_unbuf_select) high_byte |= (0x01 << 6);
if(gain_select) high_byte |= (0x01 << 5);
high_byte |= ((dac_data >> 8) & 0x0F);
low_byte |= dac_data;
SPI_master_byte(high_byte);
SPI_master_byte(low_byte);
CS = 1;
LDAC = 0; /**Latch the Data*/
LDAC = 1;
}
This is what I did in a similar case, this example is for writing an I²C driver:
// Structure holding information about an I²C bus
struct IIC_BUS
{
int pin_index_sclk;
int pin_index_sdat;
};
// Initialize I²C bus structure with pin indices
void iic_init_bus( struct IIC_BUS* iic, int idx_sclk, int idx_sdat );
// Write data to an I²C bus, toggling the bits
void iic_write( struct IIC_BUS* iic, uint8_t iicAddress, uint8_t* data, uint8_t length );
All pin indices are declared in an application-dependent header file to allow quick overview, e.g.:
// ...
#define MY_IIC_BUS_SCLK_PIN 12
#define MY_IIC_BUS_SCLK_PIN 13
#define OTHER_PIN 14
// ...
In this example, the I²C bus implementation is completely portable. It only depends on an API that can write to the chip's pins by index.
Edit:
This driver is used like this:
// main.c
#include "iic.h"
#include "pin-declarations.h"
main()
{
struct IIC_BUS mybus;
iic_init_bus( &mybus, MY_IIC_BUS_SCLK_PIN, MY_IIC_BUS_SDAT_PIN );
// ...
iic_write( &mybus, 0x42, some_data_buffer, buffer_length );
}
In one shop I worked at, the pin definitions were put into a processor specific header file. At another shop, I broke the header files into themes associated with modules in the processor, such as DAC, DMA and USB. A master include file for the processor included all of these themed header files. We could model different varieties of the same processor by include different module header files in the processor file.
You could create an implementation header file. This file would define I/O pins in terms of the processor header file. This gives you one layer of abstraction between your application and the hardware. The idea is to loosely couple the application from hardware as much as possible.
If only the driver needs to know about the CS pin, then the declaration should not appear in the header, but within the driver module itself. Code re-use is best served by hiding data at the most restrictive scope possible.
In the event that an external module needs to control CS, add an access function to the device driver module so that you have single point control. This is useful if during debugging you need to know where and when an I/O pin is being asserted; you only have one point to apply instrumentation or breakpoints.
The answer with the run-time configuration will work for a decent CPU like ARM, PowerPC...but the author is running a 8051 here. #define is probably the best way to go. Here's how I would break it down:
blah.h:
#define CSN_LOW() CS = 0
#define CSN_HI() CS = 1
#define LATCH_STROBE() \
do { LDAC = 0; LDAC = 1; } while (0)
blah.c:
#include <blah.h>
void blah_update( U8 high, U8 low )
{
CSN_LOW();
SPI_master_byte(high);
SPI_master_byte(low);
CSN_HI();
LATCH_STROBE();
}
If you need to change the pin definition, or moved to a different CPU, it should be obvious where you need to update. And it's also helps when you have to adjust the timing on the bus (ie. insert a delay here and there) as you don't need to change all over the place. Hope it helps.

Resources