LusoRobótica - Robótica em Português
Sistemas específicos => ARM => Tópico iniciado por: StarRider em 08 de Dezembro de 2010, 13:29
-
Boas,
Não sei se já conhecem, de qualquer forma vale uma vista de olhos para quem usa a "linguagem" Arduino e quer
evoluir para um ARM e continuar a usar programação 100% compatível "á la" Arduino
http://leaflabs.com/devices/maple/ (http://leaflabs.com/devices/maple/)
Abraços
PA
-
Dois tópicos abaixo deste...
Maple - ARM Cortex-M3 (Programmable with Arduino Language)
Isso teoricamente é bonito, mas na prática estão a fazer pior ainda que as bibliotecas do arduino e a esconder a porcaria com um clock mais elevado...
Nem o i2c é nativo é bit-banged se achas isso bom...
-
Para evoluir eu diria o mbed ou mesmo aprender o nativo
-
Dois tópicos abaixo deste...
Maple - ARM Cortex-M3 (Programmable with Arduino Language)
Isso teoricamente é bonito, mas na prática estão a fazer pior ainda que as bibliotecas do arduino e a esconder a porcaria com um clock mais elevado...
Nem o i2c é nativo é bit-banged se achas isso bom...
Boas,
Não disse que era bom nem que era mau, apesar de ter "hands on" com o dito cujo... mas sei que o que para uns é mau para outros é bom, e
temos que respeitar isso mesmo, pois só assim podemos também ser respeitados.
De resto, e em especial para todos os que comentam apenas numa sabe teórica, volto a dizer, nada como experimentar para depois comentar...
Abraços
PA
-
O criador deles posta muito no forum dos Arduinos, das primeiras coisas que ele disse é que as bibliotecas CMSIS não valem nada, passados 6 meses apresenta i2c bitbanged quando todos os arm's têm pelo menos um i2c nativo, mas tem mais falhas, obviamente tal como o arduino podes programar algo sem perceber nada do que está por baixo, e ai tem sempre os seus pontos positivos, mas tem sempre falhas.
-
Para evoluir eu diria o mbed ou mesmo aprender o nativo
Boas,
Para mim, e penso que sobre isso nem sequer existe lugar a duvida, passar de um AVR para um ARM é evolução, mesmo que se continue preso
a uma qualquer linguagem. Agora, se por "evoluir" entendes como base o "espartilho" do Arduino, pois ai para evoluir nem sequer é necessário
trocar de uC, basta usar um verdadeiro compilador de C/C++ com o AVR instalado nas placas Arduino.
Por outro lado, quem usa a "linguagem" Arduino e quer ter mais PODER DE PROCESSAMENTO e todas as vantagens dos periféricos do STM32F
sem ter que passar por uma curva de aprendizagem longa e penosa, pois é óbvio que por qualquer que seja o ângulo de analise será sempre
uma evolução.
Pode não ser o "passo seguinte" ideal, esse seria de facto evoluir para uma base nativa de C/C++ e usar toda a potencialidade do uC, mas
pelo menos é um "empurram" na direcção certa.
Cumprimentos,
PA
-
O criador deles posta muito no forum dos Arduinos, das primeiras coisas que ele disse é que as bibliotecas CMSIS não valem nada, passados 6 meses apresenta i2c bitbanged quando todos os arm's têm pelo menos um i2c nativo, mas tem mais falhas, obviamente tal como o arduino podes programar algo sem perceber nada do que está por baixo, e ai tem sempre os seus pontos positivos, mas tem sempre falhas.
Boas,
Vais me desculpar mas penso que estas equivocado nesse aspecto, se consultares o esquema do Maple e a implementação do I2C vais ver
que este tem 2 portas I2C mapeadas aos pinos PB6 (SCL) e PB7 (SDA) para o I2C1 e aos pinos PB10 (SCL) e PB11 (SDA) para o I2C1 que
correspondem exactamente ao periféricos I2C do STM32 F103RB.
Por outro lado, a implementação dos drivers ainda não esta completa nem disponível, pelo que não sei de onde vem essa informação que
o Maple usa bitbanged, tanto mais que toda a informação no site aponta no sentido totalmente oposto:
http://static.leaflabs.com/pub/leaflabs/maple-hardware/rev3/maple-rev3-schematics.pdf (http://static.leaflabs.com/pub/leaflabs/maple-hardware/rev3/maple-rev3-schematics.pdf)
http://leaflabs.com/docs/maple/i2c (http://leaflabs.com/docs/maple/i2c)
Penso que o projecto Maple tem uma mais valia e que o seu autor merece o nosso aplauso, seja qual for a nossa posição perante a filosofia
"Arduino" e seus clones.
Abraços,
PA
-
Today is a great day! I2C (software bit banged I2C - not hardware DMA) is working on the Maple.
The alpha software released, for testing only, from Leaflabs is working on my Maxim-IC RTC (DS3231/DS1307).
Other devices are in the process of being tested?
They needed an Arduino hacker to show them how to make it work- right!!!!
Daqui:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274652722/180 (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274652722/180)
E penso que ainda não passou de bitbanged para a frente, mas isso se tens o IDE instalado podes procurar no respectivo .h e .c/.cpp como é.
-
Today is a great day! I2C (software bit banged I2C - not hardware DMA) is working on the Maple.
The alpha software released, for testing only, from Leaflabs is working on my Maxim-IC RTC (DS3231/DS1307).
Other devices are in the process of being tested?
They needed an Arduino hacker to show them how to make it work- right!!!!
Daqui:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274652722/180 (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274652722/180)
E penso que ainda não passou de bitbanged para a frente, mas isso se tens o IDE instalado podes procurar no respectivo .h e .c/.cpp como é.
Boas,
Penso que na fase actual do projecto Maple a ideia é mesmo usar I2C por hardware, pois realmente usar bitbanged é uma estupidez e um
desperdício de recursos.
Por outro lado, estava aqui a olhar para as boards STM32-Discovery e estava a pensar até que ponto seria possível criar umas libs, defines e
alterar o startup de modo a compilar "código" Arduino no Keil (ou noutra toolchain) ... é perfeitamente viável, haja tempo e pachorra... vamos
ver no que dá.
Abraços,
PA
-
E porque é que não fazes como o tipico programador de micro-controladores, fazes uma série de funções para inicializar o que queres usar, e depois mais umas quantas funções para as usar, olha este exemplo super simples para inicializar e mandar caracteres ou strings via serial num atmega328, mais limpo é complicado, só se fizesse em assembly, é limpinho e simples de usar, comparado por exemplo com a biblioteca serial do arduino é mil vezes mais limpo e leve, está bem que não faz metade coisas que faz a serial do arduino, mas se precisas de mais uso o sprintf ou faço um sprintf levezinho.
#include "USART.h"
#include <avr/io.h>
#define BAUDRATE 9600
#define BAUD_PRESCALLER (((F_CPU / (BAUDRATE * 16UL))) - 1)
void USART_init(void){
UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8);
UBRR0L = (uint8_t)(BAUD_PRESCALLER);
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (3<<UCSZ00);
}
unsigned char USART_receive(void){
while(!(UCSR0A & (1<<RXC0)));
return UDR0;
}
void USART_putchar( unsigned char data){
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
}
void USART_putstring(char* StringPtr)
{
while (*StringPtr != 0x00) {
USART_putchar(*StringPtr);
StringPtr++;
}
}
-
E porque é que não fazes como o tipico programador de micro-controladores, fazes uma série de funções para inicializar o que queres usar, e depois mais umas quantas funções para as usar, olha este exemplo super simples para inicializar e mandar caracteres ou strings via serial num atmega328, mais limpo é complicado, só se fizesse em assembly, é limpinho e simples de usar, comparado por exemplo com a biblioteca serial do arduino é mil vezes mais limpo e leve, está bem que não faz metade coisas que faz a serial do arduino, mas se precisas de mais uso o sprintf ou faço um sprintf levezinho.
Boas,
A ideia de "compilar código Arduino" no Keil era puramente académica e o seu único propósito era demonstrar que se pode fazer coisas numa
toolchain ARM de forma fácil e rápida...
Esse forma de usar a UART é realmente simples, mas por vezes pode ser simples de mais, não tens tratamento de erros, não contemplas timeouts
e mais outras questões que por vezes em determinados projectos têm mesmo que ser contemplados.
Usamos a UART (e I2C) por intermédio de interrupts e com uma circular buffer para enviar e receber dados em background independente do flow
do firmware. É uma solução mas pesada mas com muitas vantagens, mas como disse tudo dependo da finalidade do código que estás a
desenvolver e se vai ser utilizado num sistema critico ou num simples projecto caseiro.
Aqui fica um exemplo do que usamos por estes lados:
#include "LPC22xx.h"
#include "orbiter_548P.h"
#include <string.h>
#include <stdio.h>
#include <setjmp.h>
//----- USARTS buffers
typedef struct {
uint8 r_buffer[RXBUFSIZE];
int16 rw_index,rr_index,r_count;
int8 r_buffer_overflow;
uint8 t_buffer[TXBUFSIZE];
int16 tw_index,tr_index,t_count;
} TUART;
TUART uart0;
TUART uart1;
extern volatile int16 SystemReady;
extern TSetup TheOrbiter;
extern uint8 Keybuffer;
jmp_buf i2cerror;
//=============================================================================
// UARTS
//=============================================================================
//-----------------------------------------------------------------------------
// UART0 Interrupt handler
void uart0int (void) __irq
{
unsigned char chr,iir;
iir=U0IIR; // reading U0IIR will clear the interrupt flags
switch(iir & 0x0F) {
case 0x06: // Receive line status/error
chr=U0LSR; // read U0LSR to clear the interrupt flag
break;
case 0x04: // Receive data available
chr=U0RBR;
if (chr==6) { // ACK get system ready
if (SystemReady)
PutCharUART0(TheOrbiter.Burst ? 'A' : 'P');
else
PutCharUART0('0');
} else {
uart0.r_buffer[uart0.rw_index]=chr;
if (++uart0.rw_index == RXBUFSIZE)
uart0.rw_index=0;
if (++uart0.r_count == RXBUFSIZE) {
uart0.r_count=0;
uart0.r_buffer_overflow=1;
}
}
break;
case 0x0C: // Character time out
chr=U0RBR; // read U0RBR to clear the interrupt flag
break;
case 0x02: // THRE interrupt tx buffer empty
U0THR = uart0.t_buffer[uart0.tr_index];
if (++uart0.tr_index == TXBUFSIZE)
uart0.tr_index=0;
uart0.t_count--;
if (uart0.t_count==0)
U0IER = UIERRBR; //Disable tx buf empty interrupt
break;
default:
break;
}
VICVectAddr = 0; // Acknowledge Interrupt
}
//-----------------------------------------------------------------------------
//
#pragma diag_suppress 550
void InitUARTS(void)
{
uint8 dummy;
//===== UART0
memset(&uart0,0,sizeof(TUART)); //Clear uarto control structure
PINSEL0_bit->P0_0=0x1; // Set pin function to TxD (UART0)
PINSEL0_bit->P0_1=0x1; // Set pin function to RxD (UART0)
//Disable UART INTs
U0IER = 0;
//Set baudrate
U0LCR_bit->DLAB = 1;
U0DLL = USBBAUDRATE; //U0DLL = USBBAUDRATE & 0x00ff;
U0DLM = 0; //U0DLM = USBBAUDRATE >> 8) & 0x00ff;
U0LCR_bit->DLAB = 0;
//Set mode
U0LCR = 0x3; //8 bit word length 1 stop bit No parity
//Disable the FIFO
U0FCR = 0x00;
//Set VIC
VICVectAddr3 = (unsigned int)&uart0int;
VICVectCntl3 = 0x20 | INT_UART0; // Enable vector interrupt for UART0.
VICIntEnable = INT_UART0_bit; // Enable UART0 interrupt.
// Ensure that no interrupts sources are active
dummy = U0LSR;
//Enable UART0 interrupts
U0IER = UIERRBR; //Enable byte received interrupt, Tx buf empty interrupt only active if date to send is present.
#pragma diag_default 550
//-----------------------------------------------------------------------------
//
void PutCharUART0(unsigned char byte)
{
while(uart0.t_count==TXBUFSIZE)
; // do nothing
#ifdef NOINTGUIDING
ProcessGuiding(); // EGNOS project
#endif
if (uart0.t_count || ((U0LSR & ULSRTHRE)==0)) {
DisableInts();
uart0.t_buffer[uart0.tw_index]=byte;
uart0.t_count++;
if (++uart0.tw_index==TXBUFSIZE)
uart0.tw_index=0;
U0IER = UIERRBR | UIERTHRE; //Enable byte received and Tx buf empty interrupt
RestoreInts();
} else
U0THR = byte;
}
//---------------------------------------------------------------------------
//
void PutStringUART0(char *data)
{
while(*data )
PutCharUART0(*data++);
}
//-----------------------------------------------------------------------------
//
uint8 GetCharUART0(int8 wait)
{
uint8 data=0;
if (uart0.r_count==0) {
if (wait) {
while(uart0.r_count==0)
; // Do nothing! - TODO: control Timeout
} else
return 0;
}
#ifdef NOINTGUIDING
ProcessGuiding(); // EGNOS project
#endif
DisableInts();
data=uart0.r_buffer[uart0.rr_index];
if (++uart0.rr_index == RXBUFSIZE)
uart0.rr_index=0;
uart0.r_count--;
RestoreInts();
return data;
}
//------------------------------------------------------------------------------
// Peek a char
uint8 PeekUART0(void)
{
if (uart0.r_count)
return uart0.r_buffer[uart0.rr_index];
else
return 0;
}
//------------------------------------------------------------------------------
// Clean Uart
void ClearUART0(void)
{
while (GetCharUART0(0));
}
//------------------------------------------------------------------------------
//
int16 GetStringUART0(char *buffer, int16 length)
{
int16 count=0,timeleft=32000;
uint8 chr;
if (uart0.r_count) {
length--;
do {
chr=GetCharUART0(0);
if (chr && chr!=SUFIXCHAR) {
buffer[count++]=chr;
timeleft=32000; // reset timer
} else {
timeleft--;
}
} while ((chr!=SUFIXCHAR) && (chr!='#') && (count<length) && timeleft);
if (!timeleft)
count=0;
buffer[count]=0;
}
return count;
}
//=============================================================================
// I2C
//=============================================================================
#define STA 0x20
#define SIC 0x08
#define SI 0x08
#define STO 0x10
#define STAC 0x20
#define AA 0x04
//-----------------------------------------------------------------------------
//
void InitI2C(void)
{
I2CONCLR = 0xFF;
PINSEL0 |= 0x50; // Set pinouts as scl and sda
I2SCLL =19; //speed at 100Khz for a VPB Clock Divider = 4 at 14 MHz
I2SCLH =19;
// I2SCLL=60; //speed at 375Khz for a VPB Clock Divider = 1
// I2SCLH=70; // Pierre Seguin's origional values.
I2CONSET = 0x40; //Active Master Mode on I2C bus
}
//-----------------------------------------------------------------------------
//
void StopI2C(void)
{
I2CONCLR = SIC;
I2CONSET = STO;
while((I2CONSET&STO)) ; // wait for Stopped bus I2C
}
//-----------------------------------------------------------------------------
//
void SetAddressI2C(unsigned char Addr_S)
{
unsigned char r;
I2CONCLR = 0xFF; // clear I2C - included if User forgot to "StopI2C()"
// else this function would hang.
I2CONSET = 0x40; // Active Master Mode on I2C bus
if((Addr_S & 0x01)) // test if it's reading
I2CONSET = STA | AA; // set STA - allow master to acknowlege slave;
else
I2CONSET = STA; // set STA dont allow acknowledges;
while(I2STAT!=0x08) ; // Wait for start to be completed
I2DAT = Addr_S; // Charge slave Address
I2CONCLR = SIC | STAC; // Clear i2c interrupt bit to send the data
while( ! ( I2CONSET & SI)) ; // wait till status available
r=I2STAT; // read Status. See standard error codes pdf (link in manual).
if(!(Addr_S & 0x01)) { // if we are doing a write
if (r != 0x18) { // look for "SLA+W has been transmitted; ACK has been received"
if ( r==0x20 ) // check for "SLA+W has been transmitted; NOT ACK has been received"
longjmp(i2cerror,1); // no acknowlege - probably no device there. Return a 1 in longjmp
longjmp(i2cerror,r); // other error - return status code in longjmp
}
} else {
if (r != 0x40) { // look for "SLA+R has been transmitted; ACK has been received"
if ( r==0x48 ) // check for "SLA+R has been transmitted; NOT ACK has been received"
longjmp(i2cerror,1); // no acknowlege - probably no device there. Return a 1 in longjmp
longjmp(i2cerror,r); // other error - return status code in longjmp
}
}
}
//-----------------------------------------------------------------------------
//
uint8 ReadI2C(void)
{
uint8 r;
I2CONCLR = SIC; // clear SIC;
while( ! (I2CONSET & 0x8)); // wait till status available
r=I2STAT; // check for error
if (r != 0x50) // look for "Data byte has been received; ACK has been returned"
longjmp(i2cerror,r); // read fail
return I2DAT;
}
//-----------------------------------------------------------------------------
//
void WriteI2C(uint8 data)
{
uint8 r;
I2DAT = data; // Charge Data
I2CONCLR = 0x8; // SIC; Clear i2c interrupt bit to send the data
while( ! (I2CONSET & 0x8)); // wait till status available
r=I2STAT;
if (r != 0x28) // look for "Data byte in S1DAT has been transmitted; ACK has been received"
longjmp(i2cerror,r); // write fail
}
//-----------------------------------------------------------------------------
/*====================================================================================*/
// EOF uart_i2c_drv.cpp