AVR UART - Java Android bluetooth communication - bluetooth

I have bluetooth module connected to AVR (Atmega32A) via UART. Some bytes that are transmit from bluetooth module to AVR are not properly recived.
For example the bytes that are properly transmit/recived (UTF-8):
Bluetooth module transmit byte X->recived byte X'
'w'->'w'
's'->'s'
'z'->'z'
'm'->'m'
bytes recived not properly:
'q'->'y'
'p'->'~'
'1'->'9'
Bluetooth connection settings:
Bps/Par/Bits: 115200 8N1
init UART:
#define F_CLK 16000000
#define BAUD 115200
uint16_t ubrr_value = (uint16_t) (((F_CLK)/(16 * BAUD)) - 1);
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);
// 8 bit frame, async mode
UCSRC=(1<<URSEL) | (3<<UCSZ0);
//recive and transmit mode
UCSRB = (1<<TXEN) | (1 << RXEN);
transmit/recive byte by uart:
char USART_ReceiveByte()
{
while(!(UCSRA & (1<<RXC)));
return UDR;
}
void uart_sendRS(char VALUE)
{
while(!(UCSRA & (1<<UDRE)));
UDR = VALUE;
}
main loop:
while(1)
{
recivedByte = USART_ReceiveByte();
uart_sendRS(recivedByte);
}
i would be so glad to know why it does not work properly
EDIT: if i change the order there is result:
'y'->'y'
'~'->'~'
'9'->'9'
EDIT2: probably there is something wrong with setting UBRRL and UBRRH (ubrr_value = 7 in this case), does someone can confirm if it is proper and if the microcontroller can handle such a high BAUD?
#define F_CLK 16000000
#define BAUD 115200
uint16_t ubrr_value = (uint16_t) (((F_CLK)/(16 * BAUD)) - 1);
UBRRL = ubrr_value;
UBRRH = (ubrr_value>>8);

The problem here is that you are not initialising the UART properly. You need to set the U2X bit in UCSRA if you wish to use the baud rate as you wish it configured. If you are using avr-libc you may use the following code to properly compute the BAUD rate.
void uart0_init(void) {
# define BAUD 115200
# include <util/setbaud.h>
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
# if USE_2X
UCSRA |= _BV(U2X);
# else
UCSRA &= ~_BV(U2X);
# endif
# undef BAUD
/* other uart stuff you may need */
}
If you look at the datasheet for your microcontroller, section 20.12, you will find a table with this information precomputed for you. Cheers.

Related

Linux usb serial line input may lose the trailing new line

I am testing a serial communication protocol based on printable characters only.
The setup has a pc connected to an arduino board by USB. The PC USB serial is operated in canonical mode, with no echo, no flow control, 9600 baud.
Since a read timeout is requested, pselect is called before the serial read. The arduino board simply echoes back every received character without any processing. The PC OS is Linux Neon with kernel 5.13.0-40-generic.
When lines of a specific length are transmitted from the PC and echoed back by the arduino, they are received correctly except for the final new line that is missing.
A further read, returns an empty line (the previously missing NL).
Lines with different length are transmitted and received correctly, including the trailing NL.
This behavior is fully repeatable and stable. The following code reproduce the problem for a line transmitted with a length of 65 characters (including NL) and received with a length of 64 (NL missing). Other line lengths work fine.
Thanks for any hints.
/* remote serial loop test 20220626 */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#define TX_MINLEN 63
#define TX_MAXLEN 66
#define DATA_MAXLEN 128
#define LINK_DEVICE "/dev/ttyUSB0"
#define LINK_SPEED B9600
#define RECEIVE_TIMEOUT 2000
int main()
{
int wlen;
int retval;
int msglen;
uint8_t tx_data[257] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
for (int i=16; i < 256; i++) tx_data[i] = tx_data[i & 0xf];
uint8_t rx_data[257];
/* serial interface */
char * device;
int speed;
int fd;
fd_set fdset;
struct timespec receive_timeout;
struct timespec *p_receive_timeout = &receive_timeout;
struct termios tty;
/* open serial device in blocking mode */
fd = open(LINK_DEVICE, O_RDWR | O_NOCTTY);
if (fd < 0) {
printf("Error opening %s: %s\n",LINK_DEVICE,strerror(errno));
return -1;
}
/* prepare serial read by select to have read timeout */
FD_ZERO(&(fdset));
FD_SET(fd,&(fdset));
if (RECEIVE_TIMEOUT >= 0) {
p_receive_timeout->tv_sec = RECEIVE_TIMEOUT / 1000;
p_receive_timeout->tv_nsec = RECEIVE_TIMEOUT % 1000 * 1000000;
}
else
p_receive_timeout = NULL;
/* get termios structure */
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
/* set tx and rx baudrate */
cfsetospeed(&tty, (speed_t)LINK_SPEED);
cfsetispeed(&tty, (speed_t)LINK_SPEED);
/* set no modem ctrl, 8 bit, no parity, 1 stop */
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* canonical mode: one line at a time (\n is line terminator) */
tty.c_lflag |= ICANON | ISIG;
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
/* input control */
tty.c_iflag &= ~IGNCR; /* preserve carriage return */
tty.c_iflag &= ~INPCK; /* no parity checking */
tty.c_iflag &= ~INLCR; /* no NL to CR traslation */
tty.c_iflag &= ~ICRNL; /* no CR to NL traslation */
tty.c_iflag &= ~IUCLC; /* no upper to lower case mapping */
tty.c_iflag &= ~IMAXBEL;/* no ring bell at rx buffer full */
tty.c_iflag &= ~(IXON | IXOFF | IXANY);/* no SW flowcontrol */
/* no output remapping, no char dependent delays */
tty.c_oflag = 0;
/* no additional EOL chars, confirm EOF to be 0x04 */
tty.c_cc[VEOL] = 0x00;
tty.c_cc[VEOL2] = 0x00;
tty.c_cc[VEOF] = 0x04;
/* set changed attributes really */
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
/* wait for serial link hardware to settle, required by arduino reset
* triggered by serial control lines */
sleep(2);
/* empty serial buffers, both tx and rx */
tcflush(fd,TCIOFLUSH);
/* repeat transmit and receive, each time reducing data length by 1 char */
for (int l=TX_MAXLEN; l > TX_MINLEN - 1; l--) {
/* prepare data: set EOL and null terminator for current length */
tx_data[l] = '\n';
tx_data[l+1] = 0;
/* send data */
int sent = write(fd,tx_data,l+1);
/* receive data */
/* wait for received data or for timeout */
retval = pselect(fd+1,&(fdset),NULL,NULL,p_receive_timeout,NULL);
/* check for error or timeout */
if (retval < 0)
printf("pselect error: %d - %s\n",retval,strerror(errno));
else if (retval == 0)
printf("serial read timeout\n");
/* there is enough data for a non block read: do read */
msglen = read(fd,&rx_data,DATA_MAXLEN);
/* check rx data length */
if (msglen != l+1)
printf("******** RX ERROR: sent %d, received %d\n",l+1,msglen);
else
continue;
/* check received data, including new line if present */
for (int i=0; i < msglen; i++) {
if (tx_data[i] == rx_data[i])
continue;
else {
printf("different rx data:|%s|\n",rx_data);
break;
}
}
/* clear RX buffer */
for (int i=0; i < msglen + 1; i++) rx_data[i] = 0;
}
}
When performing stream-based communication, be it via pipes, serial ports, or TCP sockets, you can never rely on reads to always return a full "unit of transmission" (in this case a line, but could also be a fixed-size block). The reason is that stream-based communication can always be split by any part of the transmission stack (even potentially the sender) into multiple blocks, and there is never a guarantee that a single read will always read a full block.
For example, you could always run into the race condition that your microcontroller is still sending parts of the message when you call read(), so not all characters are read exactly. In your case, that's not what you're seeing, because that would be more of a stochastic phenomenon (that would be worse with an increased interrupt load on the computer) and not so easily reproducible. Instead, because you're talking about the number 64 here, you're running into the static buffer size used in the kernel's tty driver that will only ever return at most 64 bytes at once, regardless of what the specified read size actually is. However, in other cases it could still be that you'll see additional failures by the kernel returning only the first couple of characters of a line in the first read(), and the rest in the second, depending on precise timing details -- you've probably not seen that yet, but it's bound to happen at some point.
The only reliable way to properly implement communication protocols in streaming situations (serial port, pipes, TCP sockets, etc.) is to consider the following:
For fixed-size data (e.g. communication units that are always N bytes in size) to loop around a read() call until you've read exactly the right amount of bytes (reads that follow an incomplete read would obviously ask for less bytes than the original read, just to make up the difference)
For variable-size data (for example communication units that are separated by a line end character) you have two options: either you read only one character at a time until you reach the end-of-line character (inefficient, uses lots of syscalls), or you keep track of the communication state via a large enough buffer that you constantly fill with read() operations until the buffer contains a line-end character, at which point you remove that line from the buffer (but keep the rest) and process that.
As a complete aside, if you're doing anything with serial communication, I can very much recommend the excellent libserialport library (LGPLv3 license) that makes working with serial ports a lot easier -- and has the benefit of being cross-platform. (Doesn't help with your issue, just thought that I'd mention it.)
Upgrading from linux kernel version 5.13.0-40-generic to 5.13.0-51-generic solved the problem.

VGA pixel grouping on STM32

I have some code that displays a single pixel on screen through VGA but am a bit stuck on how I could set multiple pixels on screen where I want them. I set up two Timers for Vertical Sync and Horizontal Sync then using the V-Sync interrupt, I set a flag to allow PA8 to toggle and output a pixel at the correct timing based on the SetCompare value I set on the timer's channel. The STM32f103c8 is also overclocked to 128MHz. Here's the code:
#include "Arduino.h"
//640x480 at 60Hz
static volatile int vflag = 0;
void setup() {
#define FLASH_ACR (*(volatile uint32_t*)(0x40022000))
FLASH_ACR = 0b110010; //enable flash prefetch and wait state to increase stability at higher freq
pinMode(PA0, PWM); //31,468.75Hz (Horizontal Sync) (Channel 1)
Timer2.pause();
Timer2.setOverflow(4067); //reload register value
Timer2.setPrescaleFactor(1); //number that divides main clock
Timer2.setCompare(1, 488); //12% duty cycle (Syncpulse/Wholeline)
Timer2.setCompare(2, 2000); //0-4067 = vertical line going left or right respectively
Timer2.attachInterrupt(2, TRIGGER);
Timer2.refresh();
Timer2.resume();
pinMode(PA6, PWM); //60Hz (Vertical Sync) (Channel 1)
Timer3.pause();
Timer3.setOverflow(4183); //reload register value
Timer3.setPrescaleFactor(510); //number that divides main clock
Timer3.setCompare(1, 16); //0.38% duty cycle (Syncpulse/Wholeframe)
Timer3.setCompare(2, 2000); //0-4183 = horizontal line going up or down respectively
Timer3.attachInterrupt(2, TRIGGER2);
Timer3.refresh();
Timer3.resume();
pinMode(PA8, OUTPUT); //need to set PinMode in order for the ODR register to work
}
void loop() {
}
void TRIGGER(){
if(vflag==1){
__asm__ volatile (
"ldr r0, =(0x4001080C) \n\t" //GPIOA base address is 0x40010800 and ODR offset is 0x0C
"ldr r1, =(1<<8) \n\t" //turn on PA8
"ldr r2, =0 \n\t" //turn off PA8
"str r1, [r0] \n\t" //turn on PA8
"str r2, [r0] \n\t" //turn off PA8
);
vflag = 0; //we set the vflag back to zero when were done outputing pixels.
}
}
I understand there's graphical defects/glitches and the code can be improved on but I'm trying to focus on how in theory this works. What I want to do is have a word display on screen, that word will be made up of letters, and those letters will be made up of groups of pixels. So then whats the best (or simplest) way to group pixels and execute them multiple times on-screen? Or how is this usually done?
I do not code for STM32 so even the code looks foreign to me however it sounds like you are hard-coding the individual pixels with timer... and generating VGA signal by some GPIO. That combination of methods is problematic to use for programmable graphics.
I am using AVR32 (UC3A with much slower clock then yours) to doing VGA image using:
screen buffer (videoram)
simply I have entire screen image stored in MCU memory. So you can simply change it contents without changing the VGA output code ...
The problem is you need to have enough memory for the image (encoded in a way to enable direct transfer to VGA connector). I am using AVR32 with 16+32+32 KByte of RAM but most MCUs have much less RAM (static images can be stored in EPROM but then it would not be possible to change the image output). So in case you do not have enough either lower resolution to fit into memory or add external memory to your system.
use integrated HW peripherial for VGA signal generation
I have more versions of VGA signal generation working:
SDRAM ... using SDRAM interface of the MCU
SMC ... using SMC interface of the MCU
SSC ... using synchronous serial interface
It all boils down to copying the screen buffer to IO interface at the VGA dot clock (~30MHz). Then on HW side combining the used MCU pins into VGA signals
for speed you can use DMA.
On top of all this you need to generate the sync signals and that is all.
So look at your MCU datasheet and find interface capable of synchronous transfer at least 3 bit data (R,G,B) with VGA dot clock speed. The closer the clock is to VGA dot clock the better (as some VGA monitors and LCDs do not tolerate too big difference)
the sync signals can be hardcoded or even encoded in the video ram.
The fastest is to use serial interface but the output is just B&W instead of RGB (unless you got 3 SSC units/channels) however you can send entire 8/16/32 pixels at once or by DMA directly so the MCU has time for other stuff and also requires much less VRAM.
My favourite is SDRAM interface (using just its data bus)
Here image from mine system:
Mine interconnection looks like this (using MCUs SDRAM interface version):
VGA <- AT32UC3A0512
R PX10 (EBI_D0)
G PX09 (EBI_D1)
B PX08 (EBI_D2)
Bright PX07 (EBI_D3)*
HS PA03
VS PA04
Here the relevant source:
VGA_EBI_SDRAMC.h:
//------------------------------------------------------------------------------------------------
#define _PA_VGA_HS 8
#define _PA_VGA_VS 16
#define _PAmo 24
volatile avr32_gpio_port_t *port_PA=&GPIO.port[AVR32_PIN_PA00>>5];
volatile U8 *SDRAM=(U8*)AVR32_EBI_CS0_ADDRESS;
//------------------------------------------------------------------------------------------------
//--- VGA 640x480x4 60Hz -------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
#define VRAM_xs 304
#define VRAM_ys 400
#define VRAM_bs 4
#define VRAM_ls (VRAM_xs>>1)
U8 VRAM[VRAM_ls*VRAM_ys];
U8 VRAM_empty[VRAM_ls];
// Horizontal timing [us]
#define VGA_t0 3
#define VGA_t1 5
#define VGA_t2 32
// Vertikal timing [lines ~31.817us] aby voslo viac bodov tak je to natiahnute na 32us++
#define VGA_ys 525
#define VGA_VS 2
#define VGA_y0 (36+40)
#define VGA_y1 (VGA_y0+VRAM_ys)
//------------------------------------------------------------------------------------------------
void VGA_init();
void VGA_screen();
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
void VGA_init()
{
system_init();
Disable_global_interrupt();
gpio_configure_pins(port_PA,_PAmo,GPIO_DIR_OUTPUT|GPIO_INIT_HIGH);
static const gpio_map_t EBI_GPIO_MAP[] =
{
{ AVR32_EBI_DATA_0_PIN, AVR32_EBI_DATA_0_FUNCTION},
{ AVR32_EBI_DATA_1_PIN, AVR32_EBI_DATA_1_FUNCTION},
{ AVR32_EBI_DATA_2_PIN, AVR32_EBI_DATA_2_FUNCTION},
{ AVR32_EBI_DATA_3_PIN, AVR32_EBI_DATA_3_FUNCTION},
};
gpio_enable_module(EBI_GPIO_MAP, sizeof(EBI_GPIO_MAP) / sizeof(EBI_GPIO_MAP[0]));
AVR32_SDRAMC.mr=0; // normal mode
AVR32_SDRAMC.tr=0; // no refresh (T=0)
AVR32_SDRAMC.cr=
(AVR32_SDRAMC_CR_NC_11_COLUMN_BITS <<AVR32_SDRAMC_CR_NC_OFFSET)
|(AVR32_SDRAMC_CR_NR_13_ROW_BITS <<AVR32_SDRAMC_CR_NR_OFFSET)
|(AVR32_SDRAMC_CR_NB_TWO_BANKS <<AVR32_SDRAMC_CR_NB_OFFSET)
|(AVR32_SDRAMC_CAS_ONE_CYCLE <<AVR32_SDRAMC_CR_CAS_OFFSET)
|(AVR32_SDRAMC_DBW_16_BITS <<AVR32_SDRAMC_CR_DBW_OFFSET)
|(0 <<AVR32_SDRAMC_TWR_OFFSET)
|(0 <<AVR32_SDRAMC_TRC_OFFSET)
|(0 <<AVR32_SDRAMC_TRP_OFFSET)
|(0 <<AVR32_SDRAMC_TRCD_OFFSET)
|(0 <<AVR32_SDRAMC_TRAS_OFFSET)
|(0 <<AVR32_SDRAMC_TXSR_OFFSET);
AVR32_SDRAMC.hsr=AVR32_SDRAMC_HSR_DA_MASK;
AVR32_SDRAMC.mdr=AVR32_SDRAMC_MDR_MD_SDRAM;
// map SDRAM CS -> memory space
AVR32_HMATRIX.sfr[AVR32_EBI_HMATRIX_NR]|=1<<AVR32_EBI_SDRAM_CS;
AVR32_HMATRIX.sfr[AVR32_EBI_HMATRIX_NR];
U32 a;
for (a=0;a<VRAM_ls*VRAM_ys;a++) VRAM[a]=0;
for (a=0;a<VRAM_ls;a++) VRAM_empty[a]=0;
}
//------------------------------------------------------------------------------------------------
void VGA_screen()
{
U32 a,x,y,c,PA,t0;
wait_start(t0);
for (;;)
{
for (PA=_PAmo,a=0,y=0;y<VGA_ys;y++)
{
wait_start(t0);
if (y== 0) PA^=_PA_VGA_VS; else PA^=0; // VS on
if (y==VGA_VS) PA^=_PA_VGA_VS; else PA^=0; // VS off
PA^=_PA_VGA_HS; // HS on
port_PA->ovrc=PA^_PAmo;
port_PA->ovrs=PA;
wait_us(t0,VGA_t0);
PA^=_PA_VGA_HS; // HS off
port_PA->ovrc=PA^_PAmo;
port_PA->ovrs=PA;
wait_us(t0,VGA_t1);
*SDRAM=0; // blank (black)
if ((y>=VGA_y0)&&(y<VGA_y1))
for (x=0;x<VRAM_ls;x++)
{
c=VRAM[a];
*SDRAM=c>>4; // write pixel into SDRAM interface (address is ignored as I use only data bus pins)
a++;
*SDRAM=c; // write pixel into SDRAM interface (address is ignored as I use only data bus pins)
}
*SDRAM=0; // blank (black)
wait_us(t0,VGA_t2);
}
}
}
//------------------------------------------------------------------------------------------------
Main.cpp:
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
#include "System\include.h"
#include "pic_zilog_inside.h"
//#include "VGA_EBI_SMC.h"
#include "VGA_EBI_SDRAMC.h"
//#include "VGA_SSC.h"
//------------------------------------------------------------------------------------------------
void pic_copy(U8 *dst,U32 dst_xs,U32 dst_ys,U32 dst_bs,U8 *src,U32 src_xs,U32 src_ys,U32 src_bs)
{
U32 x0,y0,a0,l0;
U32 x1,y1,a1,l1;
U32 a; U8 c,m;
l0=1; l1=1;
if (dst_bs==1) l0=dst_xs>>3;
if (dst_bs==2) l0=dst_xs>>2;
if (dst_bs==4) l0=dst_xs>>1;
if (dst_bs==8) l0=dst_xs;
if (src_bs==1) l1=src_xs>>3;
if (src_bs==2) l1=src_xs>>2;
if (src_bs==4) l1=src_xs>>1;
if (src_bs==8) l1=src_xs;
for (a0=0;a0<dst_ys*l0;a0++) dst[a0]=0;
for (y0=0;y0<dst_ys;y0++)
{
y1=(y0*(src_ys-1))/(dst_ys-1);
a0=l0*y0;
a1=l1*y1;
for (x0=0;x0<dst_xs;x0++)
{
x1=(x0*(src_xs-1))/(dst_xs-1);
c=0;
if (src_bs==1)
{
c=src[a1+(x1>>3)];
c>>=7-(x1&7);
c&=1;
}
if (src_bs==4)
{
c=src[a1+(x1>>1)];
if (U32(x0&1)==0) c>>=4;
c&=15;
}
if (dst_bs==1)
{
c<<=7-(x0&7);
a=a0+(x0>>3);
dst[a]|=c; if (!c) dst[a]^=c;
}
if (dst_bs==4)
{
if (c) c=15;
if (U32(x0&1)==0) { c<<=4; m=0x0F; } else m=0xF0;
a=a0+(x0>>1);
dst[a]&=m;
dst[a]|=c;
}
}
}
}
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
int main(void)
{
VGA_init();
pic_copy
(
(U8*)VRAM,
VRAM_xs,
VRAM_ys,
VRAM_bs,
(U8*)pic_zilog_inside,
pic_zilog_inside_xs,
pic_zilog_inside_ys,
pic_zilog_inside_bs
);
VGA_screen();
}
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
pic_zilog_inside.h:
const U32 pic_zilog_inside_xs=640;
const U32 pic_zilog_inside_ys=480;
const U32 pic_zilog_inside_bs=1;
const U32 pic_zilog_inside[]= // hard coded image
{
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
...
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0x80000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,
0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000001,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
};
The function pic_copy just copies hard-coded image into VRAM.
The function VGA_screen() creates the VGA signal in endless loop so other tasks must be encoded into ISRs or hard coded into pause code or between individual frames (however this is really demanding on mine setup as I got small MCU clock so there is not much room for other stuff to do). The VRAM is encoded in 16 colors (4 bits per pixel)
8 4 2 1
Brightness B G R
The brightness should just adds some voltage to R,G,B with few resistors and diodes but newer implemented it on HW side instead I have this circuit (8 colors only):
The diodes must be fast with the same barrier voltage and capacitors are 1nF. Its to avoid glitching of the image due to used interface data bus timing. Also the diodes are needed for the brightness if added in future for more info see the R2R current problem in here:
Generating square wave in AVR Assembly without PWM
[Edit1] I made huge changes in code:
//------------------------------------------------------------------------------------------------
//--- VGA EBI SDRAMC DMACA ver: 3.0 --------------------------------------------------------------
//------------------------------------------------------------------------------------------------
/*
VGA <- AT32UC3A3256
R PX10 (EBI_D0)
G PX09 (EBI_D1)
B PX08 (EBI_D2)
Bright PX07 (EBI_D3)*
/HS PX58
/VS PX59
Button PB10 (Bootloader)
debug PX54 (timing of TC00)
*/
//------------------------------------------------------------------------------------------------
//#define _Debug AVR32_PIN_PX54
#define _Button AVR32_PIN_PB10
#define _VGA_HS (1<<(AVR32_PIN_PX58&31))
#define _VGA_VS (1<<(AVR32_PIN_PX59&31))
#define _VGA_mask (_VGA_HS|_VGA_VS)
volatile avr32_gpio_port_t *port_VGA=&GPIO.port[AVR32_PIN_PX58>>5];
volatile U8 *SDRAM=(U8*)AVR32_EBI_CS0_ADDRESS;
//------------------------------------------------------------------------------------------------
//--- VGA 640x480x4 60Hz -------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
#define VRAM_xs 256
#define VRAM_ys 192
#define VRAM_bs 8
#define VRAM_ls ((VRAM_xs*VRAM_bs)>>3)
volatile static U8 VRAM[VRAM_ls*VRAM_ys];
/*------------------------------------------------------------------------------------------------
|------------------------|
| V sync |
| |----------------------|
| | V back |
| | |------------------| |
|H|H| |H|
|s|b| Video 640x480 |f|
|y|a| 525 lines |r|
|n|c| 60 Hz |o|
|c|k| |n|
| | |------------------|t|
| | V front |
|------------------------|
//----------------------------------------------------------------------------------------------*/
// VGA 640x480 60Hz H timing [pixels] dot clock = 25.175MHz
#define VGA_H_front 16
#define VGA_H_sync 96
#define VGA_H_back 48
#define VGA_H_video 640
// VGA 640x480 60Hz H timing [us] Ht = H/25.175, Hf = Vf*(VGA_V_video+VGA_V_front+VGA_V_sync+VGA_V_back)
#define VGA_Ht_front 1
#define VGA_Ht_sync 2
#define VGA_Ht_back 1
#define VGA_Hf 31500
// VGA 640x480 60Hz V timing [lines]
#define VGA_V_video 480
#define VGA_V_front 10
#define VGA_V_sync 2
#define VGA_V_back 33
#define VGA_Vf 60
//------------------------------------------------------------------------------------------------
void VGA_init();
void VGA_screen();
//------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
__attribute__((__interrupt__)) static void ISR_TC00_VGA() // TC0 chn:0 VGA horizontal frequency
{ // 8us every 31.75us -> 25% of CPU power
tc_read_sr(&AVR32_TC0,0); // more centered image requires +1 us to VGA_Ht_back -> 28% CPU power
#define y0 (VGA_V_video)
#define y1 (y0+VGA_V_front)
#define y2 (y1+VGA_V_sync)
#define y3 (y2+VGA_V_back)
#define yscr0 ((VGA_V_video>>1)-VRAM_ys)
#define yscr1 (yscr0+(VRAM_ys<<1))
static volatile U8 *p;
static volatile U32 y=y3;
#ifdef _Debug
gpio_set_gpio_pin(_Debug);
#endif
// init state
if (y>=y3){ y=0; p=VRAM; port_VGA->ovrs=_VGA_mask; }
// VS sync
if (y==y1) port_VGA->ovrc=_VGA_VS; // VS = L
if (y==y2) port_VGA->ovrs=_VGA_VS; // VS = H
// HS sync
wait_us(VGA_Ht_front); // front
port_VGA->ovrc=_VGA_HS; // HS = L
wait_us(VGA_Ht_sync); // sync
port_VGA->ovrs=_VGA_HS; // HS = H
wait_us(VGA_Ht_back); // back
// 8bit pixelformat DMACA, scan doubler + y offset
if ((y>=yscr0)&&(y<yscr1))
{
// Enable the DMACA
AVR32_DMACA.dmacfgreg = (1 << AVR32_DMACA_DMACFGREG_DMA_EN_OFFSET);
// Src Address: the source_data address
AVR32_DMACA.sar2 = (uint32_t)p;
// Dst Address: the dest_data address
AVR32_DMACA.dar2 = (uint32_t)SDRAM;
// Linked list ptrs: not used.
AVR32_DMACA.llp2 = 0x00000000;
// Channel 2 Ctrl register low
AVR32_DMACA.ctl2l =
(0 << AVR32_DMACA_CTL2L_INT_EN_OFFSET) | // Enable interrupts
(0 << AVR32_DMACA_CTL2L_DST_TR_WIDTH_OFFSET) | // Dst transfer width: 8bit (1,2 znasobi dotclock na 2x)
(0 << AVR32_DMACA_CTL2L_SRC_TR_WIDTH_OFFSET) | // Src transfer width: 8bit
(0 << AVR32_DMACA_CTL2L_DINC_OFFSET) | // Dst address increment: increment
(0 << AVR32_DMACA_CTL2L_SINC_OFFSET) | // Src address increment: increment
(0 << AVR32_DMACA_CTL2L_DST_MSIZE_OFFSET) | // Dst burst transaction len: 1 data items (each of size DST_TR_WIDTH)
(0 << AVR32_DMACA_CTL2L_SRC_MSIZE_OFFSET) | // Src burst transaction len: 1 data items (each of size DST_TR_WIDTH)
(0 << AVR32_DMACA_CTL2L_TT_FC_OFFSET) | // transfer type:M2M, flow controller: DMACA
(1 << AVR32_DMACA_CTL2L_DMS_OFFSET) | // Destination master: HSB master 2
(0 << AVR32_DMACA_CTL2L_SMS_OFFSET) | // Source master: HSB master 1
(0 << AVR32_DMACA_CTL2L_LLP_D_EN_OFFSET) | // Not used
(0 << AVR32_DMACA_CTL2L_LLP_S_EN_OFFSET); // Not used
// Channel 2 Ctrl register high
AVR32_DMACA.ctl2h =
((VRAM_ls) << AVR32_DMACA_CTL2H_BLOCK_TS_OFFSET) | // Block transfer size
(0 << AVR32_DMACA_CTL2H_DONE_OFFSET); // Not done
// Channel 2 Config register low
AVR32_DMACA.cfg2l =
(0 << AVR32_DMACA_CFG2L_HS_SEL_DST_OFFSET) | // Destination handshaking: ignored because the dst is memory
(0 << AVR32_DMACA_CFG2L_HS_SEL_SRC_OFFSET); // Source handshaking: ignored because the src is memory.
// Channel 2 Config register high
AVR32_DMACA.cfg2h =
(0 << AVR32_DMACA_CFG2H_DEST_PER_OFFSET) | // Dest hw handshaking itf: ignored because the dst is memory.
(0 << AVR32_DMACA_CFG2H_SRC_PER_OFFSET); // Source hw handshaking itf: ignored because the src is memory.
// Enable Channel 2 : start the process.
AVR32_DMACA.chenreg = ((4 << AVR32_DMACA_CHENREG_CH_EN_OFFSET) | (4 << AVR32_DMACA_CHENREG_CH_EN_WE_OFFSET));
// DMACA is messing up first BYTE so send it by SW before DMA
*SDRAM=*p;
// scan doubler increment only every second scanline
if ((y&1)==1) p+=VRAM_ls;
}
*SDRAM=0; y++;
#ifdef _Debug
gpio_clr_gpio_pin(_Debug);
#endif
#undef y0
#undef y1
#undef y2
#undef y3
}
//------------------------------------------------------------------------------------------------
void VGA_init()
{
system_init();
Disable_global_interrupt();
gpio_configure_pin(_Button,GPIO_DIR_INPUT);
#ifdef _Debug
gpio_configure_pin(_Debug,GPIO_DIR_OUTPUT);
#endif
gpio_configure_pins(port_VGA,_VGA_mask,GPIO_DIR_OUTPUT|GPIO_INIT_HIGH);
static const gpio_map_t EBI_GPIO_MAP[] =
{
{ AVR32_EBI_DATA_0_PIN, AVR32_EBI_DATA_0_FUNCTION},
{ AVR32_EBI_DATA_1_PIN, AVR32_EBI_DATA_1_FUNCTION},
{ AVR32_EBI_DATA_2_PIN, AVR32_EBI_DATA_2_FUNCTION},
{ AVR32_EBI_DATA_3_PIN, AVR32_EBI_DATA_3_FUNCTION},
};
gpio_enable_module(EBI_GPIO_MAP, sizeof(EBI_GPIO_MAP) / sizeof(EBI_GPIO_MAP[0]));
AVR32_SDRAMC.mr=0; // normal mode
AVR32_SDRAMC.tr=0; // no refresh (T=0)
AVR32_SDRAMC.cr=
(AVR32_SDRAMC_CR_NC_11_COLUMN_BITS <<AVR32_SDRAMC_CR_NC_OFFSET)
|(AVR32_SDRAMC_CR_NR_13_ROW_BITS <<AVR32_SDRAMC_CR_NR_OFFSET)
|(AVR32_SDRAMC_CR_NB_TWO_BANKS <<AVR32_SDRAMC_CR_NB_OFFSET)
|(AVR32_SDRAMC_CAS_ONE_CYCLE <<AVR32_SDRAMC_CR_CAS_OFFSET)
|(AVR32_SDRAMC_DBW_16_BITS <<AVR32_SDRAMC_CR_DBW_OFFSET)
|(0 <<AVR32_SDRAMC_TWR_OFFSET)
|(0 <<AVR32_SDRAMC_TRC_OFFSET)
|(0 <<AVR32_SDRAMC_TRP_OFFSET)
|(0 <<AVR32_SDRAMC_TRCD_OFFSET)
|(0 <<AVR32_SDRAMC_TRAS_OFFSET)
|(0 <<AVR32_SDRAMC_TXSR_OFFSET);
AVR32_SDRAMC.hsr=AVR32_SDRAMC_HSR_DA_MASK;
AVR32_SDRAMC.mdr=AVR32_SDRAMC_MDR_MD_SDRAM;
// map SDRAM CS -> memory space
AVR32_HMATRIX.sfr[AVR32_EBI_HMATRIX_NR]|=1<<AVR32_EBI_SDRAM_CS;
AVR32_HMATRIX.sfr[AVR32_EBI_HMATRIX_NR];
for (U32 a=0;a<VRAM_ls*VRAM_ys;a++) VRAM[a]=0;
timer_init(&AVR32_TC0,0,VGA_Hf,ISR_TC00_VGA,0);
Enable_global_interrupt();
}
//------------------------------------------------------------------------------------------------
Now its enough to call VGA_init(); and the stuff runs in background using Timer and DMA between internal RAM and EBI SDRAM interface. It uses only 25% of CPU power in current configuration. However half of VRAM is wasted as only 4 bits are used so high nibel might be used for back buffering to compensate. I also downclock the stuf to 66MHz as I do not have enough RAM for higher resolutions.

Mbed SPI Communication with Digital Sensor

I have a Mbed and a digital gyroscope sensor. I want to make sure two of them communications through SPI where Mbed (master) able to read the data from the gyroscope sensor (slave). Can anyone help out?
#include "mbed.h"
SPI spi(p5, p6, p7); // mosi, miso, sclk
DigitalOut cs(p8);
Serial pc(USBTX, USBRX);
int main() {
// Slave select disabled //
cs = 1;
// Setup the spi for 8 bit data, high steady state clock,
// Second edge capture, with a 1MHz clock rate
spi.format(8,3);
spi.frequency(500000);
// Slave select enabled, it is active low //
cs = 0;
// Send 0x8F, the command to read the WHO_AM_I register //
// 0x8F 1000 1111, MSB = 0 means write and MSB = 1 means read //
spi.write(0x8F);
// Send a dummy byte to receive the contents of the WHO_AM_I register //
// The default response 1101 0011 //
int whoami = spi.write(0x00);
pc.printf("WHOAMI register = 0x%X\n", whoami);
// Slave select disabled //
cs = 1;
while(1) {
cs = 0 ;
// 0x28 is the register for OUT_X_L of the gyroscope //
spi.write(0x28);
int data = spi.write(0x00);
pc.printf("data output 0x%X\n", data);
wait(0.5);
cs = 1;
}
}
A longshot answer. The gyro spec may specify a time between CS goes low and you can start sending data. Hence, try with a delay after cs = 0;
Secondly, why are you setting MSB when you intend to read WHO_AM_I register. MSB=1 is for writing and not reading.

STM32F4 ADXL345 I2C communication

I have started to work on I2C communication by examining adxl345 sensor. I wrote basic code to test if my code works or not. According to the ADXL345 technical documentation, the 0x00 register should return device id which is 0xE5.When I tried this register , the return value is 0. This application should be basic but I guess , I still missing something. Beside my experience, I also make a search at this community about the adxl345 problems,but I could not find answer. I would be very appreciated if you guide me in this problems. I attached my code.
void SysTick_Handler(void){
HAL_IncTick();
HAL_SYSTICK_IRQHandler();}
void SysClockEn();
/*System Configuration PA8-> I2C Clock , PC9-> I2C Data Lane*/
int main(){
SysClockEn();
HAL_Init();
/*------GPIO Configuration For I2C3------*/
__GPIOA_CLK_ENABLE();
GPIO_InitTypeDef *ptrB6,addrB6;
ptrB6 = &addrB6;
ptrB6->Alternate = GPIO_AF4_I2C3;
ptrB6->Pin = GPIO_PIN_8;
ptrB6->Pull = GPIO_NOPULL;
ptrB6->Speed =GPIO_SPEED_FREQ_HIGH;
ptrB6->Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOA,ptrB6);
__GPIOC_CLK_ENABLE();
GPIO_InitTypeDef *ptrC,addrC;
ptrC = &addrC;
ptrC->Alternate =GPIO_AF4_I2C3;
ptrC->Mode =GPIO_MODE_AF_OD;
ptrC->Pin =GPIO_PIN_9;
ptrC->Pull =GPIO_NOPULL;
ptrC->Speed =GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC,ptrC);
/*-----I2C Configurations-----*/
//__HAL_RCC_I2C3_CLK_ENABLE();
__I2C3_CLK_ENABLE();
I2C_HandleTypeDef *ptrI2C,addrI2C;
ptrI2C = &addrI2C;
ptrI2C->Instance = I2C3;
ptrI2C->Init.ClockSpeed = 100000; //100Khz
ptrI2C->Init.DutyCycle = I2C_DUTYCYCLE_2;
ptrI2C->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
ptrI2C->Mode =HAL_I2C_MODE_MASTER;
//ptrI2C->Init.GeneralCallMode =I2C_GENERALCALL_DISABLE;
//ptrI2C->Init.NoStretchMode=I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(ptrI2C);
__HAL_I2C_ENABLE(ptrI2C);
uint8_t data=0x00;
unsigned char buffer[2];
uint8_t *buf;
unsigned char pt;
uint32_t ptr;
uint8_t val
while(1){
val=HAL_I2C_IsDeviceReady(ptrI2C,0x1D,0xe5,1000);
pt=HAL_I2C_GetState(ptrI2C);
//HAL_I2C_Master_Transmit(ptrI2C,0x1d,0x00,1,0);
//HAL_I2C_Master_Receive(ptrI2C,0x1d,buffer,1,100);
//HAL_Delay(2);
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
ptr=HAL_I2C_GetError(ptrI2C);
}
}
void SysClockEn(){
__PWR_CLK_ENABLE();
}
The documentation of the sensor says:
the 7-bit I2C address for the device is 0x1D
So in your code your should write:
#define SensAddr (0x1D<<1)
...
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
...
This is because ST HAL considers the 7 bit address left shifted.
The documentation also says:
An alternate I2C address of 0x53 (followed by the R/W bit) can be chosen by grounding the SDO/ALT ADDRESS
If this is the case of your hardware, change the code to:
#define SensAddr (0x53<<1)
...
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
...

Serial connection return NULL after first call

I'm trying to talk to an arduino via a rs485 serial link. I have a usb to serial rs485 adapter plugged in my pc and a max485 in the arduino side. To get started i simply uploaded a sketch that send back what it receives.
#include <SoftwareSerial.h>
#define SSerialRX 10 //Serial Receive pin
#define SSerialTX 11 //Serial Transmit pin
#define SSerialTxControl 3 //RS485 Direction control
#define RS485Transmit HIGH
#define RS485Receive LOW
#define Pin13LED 13
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
void setup()
{
pinMode(Pin13LED, OUTPUT);
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Receive);
RS485Serial.begin(300);
}//--(end setup )---
void loop()
{
if (RS485Serial.available()){
delay(100);
char x = RS485Serial.read();
digitalWrite(Pin13LED, HIGH);
digitalWrite(SSerialTxControl, RS485Transmit); // Enable RS485 Transmit
Serial.write(x);
RS485Serial.write(x);
Serial.flush();
delay(10);
digitalWrite(SSerialTxControl, RS485Receive); // Disable RS485 Transmit
digitalWrite(Pin13LED, LOW);
delay(200);
}
}//--(end main loop )---
Then, to test the connection, i run a python script in the pc that writes a character to the serial port and listens to the response:
import serial
import time
PORT1 = "/dev/ttyUSB0"
try:
rs485 = serial.Serial(PORT1, 300)
while True:
print 'loop'
rs485.write('r')
time.sleep(0.5)
data = rs485.read()
if data == '\0':
print 'null'
else:
print data
time.sleep(1)
except:
rs485.close()
The first time I launch the script it happens something like this:
giulio#giulio-vaio:~$ python rs485io.py
loop
r
loop
r
loop
^C
If i try to launch again the script, it writes nothing more than:
giulio#giulio-vaio:~$ python rs485io.py
loop
null
loop
null
loop
null
^C
It starts working again only if i reboot my pc (with ubuntu by the way). If i unplug and plug again the usb to serial converter, nothing changes, if i reboot the arduino, same story. I tried the same configuration with a raspberry pi and the result is identical. Changing usb port doesn't work, upload again the same sketch in the arduino, nothing happens.
The led on the pin 13 blinks, so the arduino is receiving and sending something, the serial.read() function returns, so something is arriving, but is (after the first time) a null carachter '\x00'. In one positive case, after rebooting, I tried to let the script go on for a few time and everything went fine, until i hitted ctrl-c and started again the script.
This is dmesg after i plug in the serial converter:
[ 6116.508264] usb 1-2.1.3: new full-speed USB device number 27 using ehci-pci
[ 6116.617247] usb 1-2.1.3: New USB device found, idVendor=1a86, idProduct=7523
[ 6116.617257] usb 1-2.1.3: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[ 6116.617264] usb 1-2.1.3: Product: USB2.0-Serial
[ 6116.617694] ch341 1-2.1.3:1.0: ch341-uart converter detected
[ 6116.621498] usb 1-2.1.3: ch341-uart converter now attached to ttyUSB0
I don't know what to do after this, any help would be appreciated.
EDIT :
the pc doesn't need to be rebooted, it works if i unload and then load again the module ch341, the one that handles the usb converter.
I added two lines at the top of the code:
subprocess.Popen("modprobe -r ch341".split()).wait()
subprocess.Popen("modprobe ch341".split()).wait()
I know it doesn't really solve the problem, but it works.
EDIT 2 :
Looking at the documentation http://lxr.free-electrons.com/source/Documentation/serial/serial-rs485.txt , I tried to send an ioctl signal to the driver, using this code in c (i'm not good with C, so please forgive me)
#include (all the libraries needed)
/* Driver-specific ioctls: */
#define TIOCGRS485 0x542E
#define TIOCSRS485 0x542F
/* Open your specific device (e.g., /dev/mydevice): */
int main(){
const char *file1 = "/dev/ttyUSB0";
const char *file2 = "output_cprog.txt";
int fd = open (file1,O_WRONLY);
if(fd < 0){
printf("%s: %s\n","error opening ttyusb",strerror( errno ) );
}
int fq = open(file2,O_WRONLY);
if( fq < 0){
printf("%s: %s\n","errore apertura file",strerror( errno ));
}
struct serial_rs485 rs485conf;
// Enable RS485 mode:
rs485conf.flags |= SER_RS485_ENABLED;
// Set logical level for RTS pin equal to 1 when sending:
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
// or, set logical level for RTS pin equal to 0 after sending:
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
// Set rts delay before send, if needed:
rs485conf.delay_rts_before_send = 10;
// Set rts delay after send, if needed:
rs485conf.delay_rts_after_send = 10;
int ioc = ioctl (fd, TIOCSRS485, &rs485conf);
if(ioc < 0){
printf("%i\n",ioc);
printf("ioctl error: %s\n", strerror( errno ));
}
char *character = "f\n";
write(fd,character,2);
char *buffer;
buffer = (char *) malloc(10);
read(fd, buffer, 1);
write(fq, buffer, 1);
printf("received character: %s\n",buffer[0]);
if( close(fd) < 0){
printf("%s: %s\n","error closing port",strerror( errno ));
}
if (close(fq) < 0){
printf("%s: %s\n","error closing file",strerror( errno ));
}
return 0;
}
but compiling and running the program what i see is only this:
giulio#giulio-vaio:~$ ./ioctlRS485.o
-1
ioctl error: Inappropriate ioctl for device
received character: (null)
I think, by looking at the driver https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c that it doesn't have the appropriate function to handle an ioctl at all.

Resources