Skip to content

Commit 09d6520

Browse files
committed
new feature; * DigitalReadSerial: Serial.println, Serial.begin all baudrates, pinMode (0-7), digitalRead (0-15)
* AnalogReadSerial: analogRead (A0, 4Hz, bits increased from 8 to 10 by multiplying with 4) * further examples work now thanks to these two * hardware bitstream enhanced with GPIO, ADC, (PWM or SPI)
1 parent 7bb0430 commit 09d6520

17 files changed

+1283
-34
lines changed

AlhambraII/picorv32/boards.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ generic.build.mcu=picorv32
88
generic.build.core=picorv32
99
generic.build.board=PICORV32_FPGA_GENERIC
1010
generic.upload.tool=iceprog
11-
generic.upload.maximum_size=9999
11+
generic.upload.maximum_size=99999
1212
generic.upload.wait_for_upload_port=false
1313
generic.upload.native_usb=false
+40-11
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,59 @@
1+
#ifndef Arduino_h
2+
#define Arduino_h
3+
14
#include <stdint.h>
25
#include <stdbool.h>
36

7+
// picorv32: work-a-round; for size_t only - original Arduino.h does NOT have this!
8+
#include <cstddef>
9+
410
#define reg_spictrl (*(volatile uint32_t*)0x02000000)
511
#define reg_uart_clkdiv (*(volatile uint32_t*)0x02000004)
612
#define reg_uart_data (*(volatile uint32_t*)0x02000008)
7-
#define reg_leds (*(volatile uint32_t*)0x03000000)
13+
#define reg_outp (*(volatile uint32_t*)0x03000000) // contains reg_leds also
14+
//#define reg_inp_zero (*(volatile uint32_t*)0x04000000)
15+
#define reg_inp (*(volatile uint32_t*)0x05000000)
816

9-
#define clk_div_s 12000000 // 1s
10-
#define clk_div_ms 12000 // 1ms
11-
#define clk_div_us 12 // 1us
12-
13-
void print(const char*);
14-
void delay(uint32_t);
17+
#define F_CPU 12000000 // 12MHz
1518

16-
void setup(void);
17-
void loop(void);
19+
#define clk_div_s (F_CPU) // 1s
20+
#define clk_div_ms (F_CPU/1000) // 1ms
21+
#define clk_div_us (F_CPU/1000000) // 1us
1822

19-
// --- --- --- make blink working
2023
#define HIGH 0x1
2124
#define LOW 0x0
2225

2326
#define INPUT 0x0
2427
#define OUTPUT 0x1
2528
#define INPUT_PULLUP 0x2
2629

27-
#define LED_BUILTIN 0x0
30+
typedef uint8_t byte;
2831

2932
void pinMode(uint8_t, uint8_t);
3033
void digitalWrite(uint8_t, uint8_t);
34+
int digitalRead(uint8_t);
35+
int analogRead(uint8_t);
36+
37+
void print(const char*);
38+
39+
unsigned long millis(void);
40+
unsigned long micros(void);
41+
void delay(unsigned long);
42+
43+
void setup(void);
44+
void loop(void);
45+
46+
#ifdef __cplusplus
47+
//#include "WCharacter.h"
48+
//#include "WString.h"
49+
#include "HardwareSerial.h"
50+
//#include "USBAPI.h"
51+
#if defined(HAVE_HWSERIAL0) && defined(HAVE_CDCSERIAL)
52+
#error "Targets with both UART0 and CDC serial not supported"
53+
#endif
54+
55+
#endif
56+
57+
#include "pins_arduino.h"
58+
59+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/*
2+
HardwareSerial.cpp - Hardware serial library for Wiring
3+
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
Modified 23 November 2006 by David A. Mellis
20+
Modified 28 September 2010 by Mark Sproul
21+
Modified 14 August 2012 by Alarus
22+
Modified 3 December 2013 by Matthijs Kooijman
23+
*/
24+
25+
/*#include <stdlib.h>
26+
#include <stdio.h>
27+
#include <string.h>
28+
#include <inttypes.h>
29+
#include <util/atomic.h>*/
30+
#include "Arduino.h"
31+
32+
#include "HardwareSerial.h"
33+
#include "HardwareSerial_private.h"
34+
35+
// this next line disables the entire HardwareSerial.cpp,
36+
// this is so I can support Attiny series and any other chip without a uart
37+
#if defined(HAVE_HWSERIAL0) //|| defined(HAVE_HWSERIAL1) || defined(HAVE_HWSERIAL2) || defined(HAVE_HWSERIAL3)
38+
39+
// SerialEvent functions are weak, so when the user doesn't define them,
40+
// the linker just sets their address to 0 (which is checked below).
41+
// The Serialx_available is just a wrapper around Serialx.available(),
42+
// but we can refer to it weakly so we don't pull in the entire
43+
// HardwareSerial instance if the user doesn't also refer to it.
44+
#if defined(HAVE_HWSERIAL0)
45+
void serialEvent() __attribute__((weak));
46+
bool Serial0_available() __attribute__((weak));
47+
#endif
48+
49+
/*#if defined(HAVE_HWSERIAL1)
50+
void serialEvent1() __attribute__((weak));
51+
bool Serial1_available() __attribute__((weak));
52+
#endif
53+
54+
#if defined(HAVE_HWSERIAL2)
55+
void serialEvent2() __attribute__((weak));
56+
bool Serial2_available() __attribute__((weak));
57+
#endif
58+
59+
#if defined(HAVE_HWSERIAL3)
60+
void serialEvent3() __attribute__((weak));
61+
bool Serial3_available() __attribute__((weak));
62+
#endif*/
63+
64+
void serialEventRun(void)
65+
{
66+
#if defined(HAVE_HWSERIAL0)
67+
if (Serial0_available && serialEvent && Serial0_available()) serialEvent();
68+
#endif
69+
/*#if defined(HAVE_HWSERIAL1)
70+
if (Serial1_available && serialEvent1 && Serial1_available()) serialEvent1();
71+
#endif
72+
#if defined(HAVE_HWSERIAL2)
73+
if (Serial2_available && serialEvent2 && Serial2_available()) serialEvent2();
74+
#endif
75+
#if defined(HAVE_HWSERIAL3)
76+
if (Serial3_available && serialEvent3 && Serial3_available()) serialEvent3();
77+
#endif*/
78+
}
79+
80+
// macro to guard critical sections when needed for large TX buffer sizes
81+
#if (SERIAL_TX_BUFFER_SIZE>256)
82+
#define TX_BUFFER_ATOMIC ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
83+
#else
84+
#define TX_BUFFER_ATOMIC
85+
#endif
86+
87+
// Actual interrupt handlers //////////////////////////////////////////////////////////////
88+
89+
/*void HardwareSerial::_tx_udr_empty_irq(void)
90+
{
91+
// If interrupts are enabled, there must be more data in the output
92+
// buffer. Send the next byte
93+
unsigned char c = _tx_buffer[_tx_buffer_tail];
94+
_tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;
95+
96+
*_udr = c;
97+
98+
// clear the TXC bit -- "can be cleared by writing a one to its bit
99+
// location". This makes sure flush() won't return until the bytes
100+
// actually got written. Other r/w bits are preserved, and zeroes
101+
// written to the rest.
102+
103+
#ifdef MPCM0
104+
*_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0);
105+
#else
106+
*_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0)));
107+
#endif
108+
109+
if (_tx_buffer_head == _tx_buffer_tail) {
110+
// Buffer empty, so disable interrupts
111+
cbi(*_ucsrb, UDRIE0);
112+
}
113+
}*/
114+
115+
// Public Methods //////////////////////////////////////////////////////////////
116+
117+
void HardwareSerial::begin(unsigned long baud, byte config)
118+
{
119+
/*// Try u2x mode first
120+
uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
121+
*_ucsra = 1 << U2X0;
122+
123+
// hardcoded exception for 57600 for compatibility with the bootloader
124+
// shipped with the Duemilanove and previous boards and the firmware
125+
// on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
126+
// be > 4095, so switch back to non-u2x mode if the baud rate is too
127+
// low.
128+
if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
129+
{
130+
*_ucsra = 0;
131+
baud_setting = (F_CPU / 8 / baud - 1) / 2;
132+
}
133+
134+
// assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
135+
*_ubrrh = baud_setting >> 8;
136+
*_ubrrl = baud_setting;
137+
138+
_written = false;
139+
140+
//set the data bits, parity, and stop bits
141+
#if defined(__AVR_ATmega8__)
142+
config |= 0x80; // select UCSRC register (shared with UBRRH)
143+
#endif
144+
*_ucsrc = config;
145+
146+
sbi(*_ucsrb, RXEN0);
147+
sbi(*_ucsrb, TXEN0);
148+
sbi(*_ucsrb, RXCIE0);
149+
cbi(*_ucsrb, UDRIE0);*/
150+
reg_uart_clkdiv = F_CPU/baud; // 104 for 115200, 1250 for 9600, etc.
151+
}
152+
153+
void HardwareSerial::end()
154+
{
155+
/*// wait for transmission of outgoing data
156+
flush();
157+
158+
cbi(*_ucsrb, RXEN0);
159+
cbi(*_ucsrb, TXEN0);
160+
cbi(*_ucsrb, RXCIE0);
161+
cbi(*_ucsrb, UDRIE0);
162+
163+
// clear any received data
164+
_rx_buffer_head = _rx_buffer_tail;*/
165+
}
166+
167+
int HardwareSerial::available(void)
168+
{
169+
/*return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;*/
170+
171+
return 0;
172+
}
173+
174+
int HardwareSerial::peek(void)
175+
{
176+
/*if (_rx_buffer_head == _rx_buffer_tail) {
177+
return -1;
178+
} else {
179+
return _rx_buffer[_rx_buffer_tail];
180+
}*/
181+
182+
return 0;
183+
}
184+
185+
int HardwareSerial::read(void)
186+
{
187+
/*// if the head isn't ahead of the tail, we don't have any characters
188+
if (_rx_buffer_head == _rx_buffer_tail) {
189+
return -1;
190+
} else {
191+
unsigned char c = _rx_buffer[_rx_buffer_tail];
192+
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
193+
return c;
194+
}*/
195+
196+
int32_t c = -1;
197+
198+
uint32_t cycles_begin, cycles_now, cycles;
199+
__asm__ volatile ("rdcycle %0" : "=r"(cycles_begin));
200+
201+
while (c == -1) {
202+
__asm__ volatile ("rdcycle %0" : "=r"(cycles_now));
203+
cycles = cycles_now - cycles_begin;
204+
if (cycles > 12000000) {
205+
cycles_begin = cycles_now;
206+
}
207+
c = reg_uart_data;
208+
}
209+
210+
return c;
211+
}
212+
213+
int HardwareSerial::availableForWrite(void)
214+
{
215+
/*tx_buffer_index_t head;
216+
tx_buffer_index_t tail;
217+
218+
TX_BUFFER_ATOMIC {
219+
head = _tx_buffer_head;
220+
tail = _tx_buffer_tail;
221+
}
222+
if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail;
223+
return tail - head - 1;*/
224+
225+
return 0;
226+
}
227+
228+
void HardwareSerial::flush()
229+
{
230+
/*// If we have never written a byte, no need to flush. This special
231+
// case is needed since there is no way to force the TXC (transmit
232+
// complete) bit to 1 during initialization
233+
if (!_written)
234+
return;
235+
236+
while (bit_is_set(*_ucsrb, UDRIE0) || bit_is_clear(*_ucsra, TXC0)) {
237+
if (bit_is_clear(SREG, SREG_I) && bit_is_set(*_ucsrb, UDRIE0))
238+
// Interrupts are globally disabled, but the DR empty
239+
// interrupt should be enabled, so poll the DR empty flag to
240+
// prevent deadlock
241+
if (bit_is_set(*_ucsra, UDRE0))
242+
_tx_udr_empty_irq();
243+
}
244+
// If we get here, nothing is queued anymore (DRIE is disabled) and
245+
// the hardware finished tranmission (TXC is set).*/
246+
}
247+
248+
size_t HardwareSerial::write(uint8_t c)
249+
{
250+
/*_written = true;
251+
// If the buffer and the data register is empty, just write the byte
252+
// to the data register and be done. This shortcut helps
253+
// significantly improve the effective datarate at high (>
254+
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
255+
if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
256+
// If TXC is cleared before writing UDR and the previous byte
257+
// completes before writing to UDR, TXC will be set but a byte
258+
// is still being transmitted causing flush() to return too soon.
259+
// So writing UDR must happen first.
260+
// Writing UDR and clearing TC must be done atomically, otherwise
261+
// interrupts might delay the TXC clear so the byte written to UDR
262+
// is transmitted (setting TXC) before clearing TXC. Then TXC will
263+
// be cleared when no bytes are left, causing flush() to hang
264+
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
265+
*_udr = c;
266+
#ifdef MPCM0
267+
*_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0);
268+
#else
269+
*_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0)));
270+
#endif
271+
}
272+
return 1;
273+
}
274+
tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE;
275+
276+
// If the output buffer is full, there's nothing for it other than to
277+
// wait for the interrupt handler to empty it a bit
278+
while (i == _tx_buffer_tail) {
279+
if (bit_is_clear(SREG, SREG_I)) {
280+
// Interrupts are disabled, so we'll have to poll the data
281+
// register empty flag ourselves. If it is set, pretend an
282+
// interrupt has happened and call the handler to free up
283+
// space for us.
284+
if(bit_is_set(*_ucsra, UDRE0))
285+
_tx_udr_empty_irq();
286+
} else {
287+
// nop, the interrupt handler will free up space for us
288+
}
289+
}
290+
291+
_tx_buffer[_tx_buffer_head] = c;
292+
293+
// make atomic to prevent execution of ISR between setting the
294+
// head pointer and setting the interrupt flag resulting in buffer
295+
// retransmission
296+
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
297+
_tx_buffer_head = i;
298+
sbi(*_ucsrb, UDRIE0);
299+
}*/
300+
301+
// reg_outp = (reg_outp & 0xFFFFFF00) | ((uint32_t)43); // reg_leds
302+
reg_uart_data = c;
303+
304+
return 1;
305+
}
306+
307+
#endif // whole file

0 commit comments

Comments
 (0)