Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
85bd7bbe
Commit
85bd7bbe
authored
Jan 23, 2016
by
Terry Ellison
Browse files
Merge pull request #951 from Alkorin/ws2812-uart
Rewrite ws2812 serialization code to use UART1 instead of bit-banging.
parents
3b589e21
51bb8a50
Changes
1
Hide whitespace changes
Inline
Side-by-side
app/modules/ws2812.c
View file @
85bd7bbe
...
@@ -4,54 +4,46 @@
...
@@ -4,54 +4,46 @@
#include "c_stdlib.h"
#include "c_stdlib.h"
#include "c_string.h"
#include "c_string.h"
#include "user_interface.h"
#include "user_interface.h"
#include "driver/uart.h"
static
inline
uint32_t
_getCycleCount
(
void
)
{
// Stream data using UART1 routed to GPIO2
uint32_t
cycles
;
// NODE_DEBUG should not be activated because it also uses UART1
__asm__
__volatile__
(
"rsr %0,ccount"
:
"=a"
(
cycles
));
return
cycles
;
}
// This algorithm reads the cpu clock cycles to calculate the correct
// pulse widths. It works in both 80 and 160 MHz mode.
// The values for t0h, t1h, ttot have been tweaked and it doesn't get faster than this.
// The datasheet is confusing and one might think that a shorter pulse time can be achieved.
// The period has to be at least 1.25us, even if the datasheet says:
// T0H: 0.35 (+- 0.15) + T0L: 0.8 (+- 0.15), which is 0.85<->1.45 us.
// T1H: 0.70 (+- 0.15) + T1L: 0.6 (+- 0.15), which is 1.00<->1.60 us.
// Anything lower than 1.25us will glitch in the long run.
static
void
ICACHE_RAM_ATTR
ws2812_write
(
uint8_t
pin
,
uint8_t
*
pixels
,
uint32_t
length
)
{
static
void
ICACHE_RAM_ATTR
ws2812_write
(
uint8_t
pin
,
uint8_t
*
pixels
,
uint32_t
length
)
{
uint8_t
*
p
,
*
end
,
pixel
,
mask
;
uint32_t
t
,
t0h
,
t1h
,
ttot
,
c
,
start_time
,
pin_mask
;
// Data are sent LSB first, with a start bit at 0, an end bit at 1 and all inverted
// 0b00110111 => 110111 => [0]111011[1] => 10001000 => 00
pin_mask
=
1
<<
pin
;
// 0b00000111 => 000111 => [0]111000[1] => 10001110 => 01
p
=
pixels
;
// 0b00110100 => 110100 => [0]001011[1] => 11101000 => 10
end
=
p
+
length
;
// 0b00000100 => 000100 => [0]001000[1] => 11101110 => 11
pixel
=
*
p
++
;
uint8_t
_uartData
[
4
]
=
{
0
b00110111
,
0
b00000111
,
0
b00110100
,
0
b00000100
};
mask
=
0x80
;
start_time
=
0
;
// Configure UART1
t0h
=
(
1000
*
system_get_cpu_freq
())
/
3022
;
// 0.35us (spec=0.35 +- 0.15)
// Set baudrate of UART1 to 3200000
t1h
=
(
1000
*
system_get_cpu_freq
())
/
1477
;
// 0.70us (spec=0.70 +- 0.15)
WRITE_PERI_REG
(
UART_CLKDIV
(
1
),
UART_CLK_FREQ
/
3200000
);
ttot
=
(
1000
*
system_get_cpu_freq
())
/
800
;
// 1.25us (MUST be >= 1.25)
// Set UART Configuration No parity / 6 DataBits / 1 StopBits / Invert TX
WRITE_PERI_REG
(
UART_CONF0
(
1
),
UART_TXD_INV
|
(
1
<<
UART_STOP_BIT_NUM_S
)
|
(
1
<<
UART_BIT_NUM_S
));
while
(
true
)
{
if
(
pixel
&
mask
)
{
// Redirect UART1 to GPIO2
t
=
t1h
;
// Disable GPIO2
}
else
{
GPIO_REG_WRITE
(
GPIO_ENABLE_W1TC_ADDRESS
,
BIT2
);
t
=
t0h
;
// Enable Function 2 for GPIO2 (U1TXD)
}
PIN_FUNC_SELECT
(
PERIPHS_IO_MUX_GPIO2_U
,
FUNC_U1TXD_BK
);
while
(((
c
=
_getCycleCount
())
-
start_time
)
<
ttot
);
// Wait for the previous bit to finish
GPIO_REG_WRITE
(
GPIO_OUT_W1TS_ADDRESS
,
pin_mask
);
// Set pin high
uint8_t
*
end
=
pixels
+
length
;
start_time
=
c
;
// Save the start time
do
{
while
(((
c
=
_getCycleCount
())
-
start_time
)
<
t
);
// Wait for high time to finish
uint8_t
value
=
*
pixels
++
;
GPIO_REG_WRITE
(
GPIO_OUT_W1TC_ADDRESS
,
pin_mask
);
// Set pin low
if
(
!
(
mask
>>=
1
))
{
// Next bit/byte
// Wait enough space in the FIFO buffer
if
(
p
>=
end
)
{
// (Less than 124 bytes in the buffer)
break
;
while
(((
READ_PERI_REG
(
UART_STATUS
(
1
))
>>
UART_TXFIFO_CNT_S
)
&
UART_TXFIFO_CNT
)
>
124
);
}
pixel
=
*
p
++
;
// Fill the buffer
mask
=
0x80
;
WRITE_PERI_REG
(
UART_FIFO
(
1
),
_uartData
[(
value
>>
6
)
&
3
]);
}
WRITE_PERI_REG
(
UART_FIFO
(
1
),
_uartData
[(
value
>>
4
)
&
3
]);
}
WRITE_PERI_REG
(
UART_FIFO
(
1
),
_uartData
[(
value
>>
2
)
&
3
]);
WRITE_PERI_REG
(
UART_FIFO
(
1
),
_uartData
[(
value
>>
0
)
&
3
]);
}
while
(
pixels
<
end
);
}
}
// Lua: ws2812.writergb(pin, "string")
// Lua: ws2812.writergb(pin, "string")
...
@@ -87,14 +79,8 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
...
@@ -87,14 +79,8 @@ static int ICACHE_FLASH_ATTR ws2812_writergb(lua_State* L)
buffer
[
i
+
1
]
=
r
;
buffer
[
i
+
1
]
=
r
;
}
}
// Initialize the output pin and wait a bit
platform_gpio_mode
(
pin
,
PLATFORM_GPIO_OUTPUT
,
PLATFORM_GPIO_FLOAT
);
platform_gpio_write
(
pin
,
0
);
// Send the buffer
// Send the buffer
ets_intr_lock
();
ws2812_write
(
pin_num
[
pin
],
(
uint8_t
*
)
buffer
,
length
);
ws2812_write
(
pin_num
[
pin
],
(
uint8_t
*
)
buffer
,
length
);
ets_intr_unlock
();
c_free
(
buffer
);
c_free
(
buffer
);
...
@@ -113,14 +99,8 @@ static int ICACHE_FLASH_ATTR ws2812_writegrb(lua_State* L) {
...
@@ -113,14 +99,8 @@ static int ICACHE_FLASH_ATTR ws2812_writegrb(lua_State* L) {
size_t
length
;
size_t
length
;
const
char
*
buffer
=
luaL_checklstring
(
L
,
2
,
&
length
);
const
char
*
buffer
=
luaL_checklstring
(
L
,
2
,
&
length
);
// Initialize the output pin
platform_gpio_mode
(
pin
,
PLATFORM_GPIO_OUTPUT
,
PLATFORM_GPIO_FLOAT
);
platform_gpio_write
(
pin
,
0
);
// Send the buffer
// Send the buffer
ets_intr_lock
();
ws2812_write
(
pin_num
[
pin
],
(
uint8_t
*
)
buffer
,
length
);
ws2812_write
(
pin_num
[
pin
],
(
uint8_t
*
)
buffer
,
length
);
ets_intr_unlock
();
return
0
;
return
0
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment