Repurpose a CC2533 hardware and code Arduino-ish

Anything not related to STM32
Post Reply
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Repurpose a CC2533 hardware and code Arduino-ish

Post by mrburnette »

Years back, I made some statement about "Arduino" being a mindset and not just an atmega processor or ArduinoIDE. I forget the context, I was 10 years younger, but I think I will stand by that statement. For your consideration:

SMART Response PE is a surplus RF device used in school systems for remote test and quiz taking. These are older tech and one finds them on eBay constantly. They are based (my units) on a TI CC2533 microcontroller with 4K of SRAM and 64K of flash and 1K words of eeprom. The CC2533 has RF but the default stack is Zigbee and I am not going to discuss that here.

The candy bar-ish enclosure runs from 2 AA batteries and the LCD is not backlit, but usable and the sample code has all of the LCD basic requirements already written: init(), clear(), line, text, inverse, etc. The default font is 5x7.

What I am going to discuss is how I am playing around with this device as-if it were an Arduino board.

Some background and things I needed to gather:
99% of this effort was done by github user: serisman and his github is located
H-E-R-E
You will need everything from that repository.

You will need the free opensource compiler/linker SDCC which can be found on the Internet. I am running it on Windows 10 64-bit, latest patches.

I strongly recommend you purchase a Texas Instrument CC Debugger ... it provides a remarkably error free upload solution, much like Arduino ISP. I found one in the U.S. for shipping and it cost me $8 delivered... consult eBay or your choice for such device clones.

A quick review:
  • we have code
    we have a compiler/linker
    we have a way to upload to the device over USB
    we assume we purchased a device or two...
Treat it like an Arduino
Many new users of Arduino know little about the under-the-hood stuff. Old people like myself came from a C programming background, through a C++ era, and into Arduino. We instinctively know that C programs all have a "main" section, but we forget about it when we use ArduinoIDE. Under the hood, Arduino has a "main" section but it stays hidden. What I am going to do is to take the CC2533 C code, section main.c from github, and modify that just a bit to make it look like it is Arduino style.

I will create a new file and call it Arduino.h

Code: Select all

// Arduino-like include to implement setup() and loop() under SDCC
// These forward declarations avoid SDCC warnings!
void setup( void );
void loop( void );

void main() {
  setup();

  while (1) {
    loop();
  }
}
Now, over in serisman's main.c code, I will make a few changes to how he structured things:

1.) I will #include our new Arduino.h file in serisman's main.c before any other inludes:

Code: Select all

#include "Arduino.h"					// Implement the construct of setup() and loop()
#include "hal.h"
#include "util.h"
#include "string_utils.h"
#include "clock.h"
#include "uart.h"
#include "display.h"
#include "keypad.h"
#include "bitmaps.h"
2.) I will prototype all of the forward declarations (done automagically by Arduino!)

Code: Select all

// forward declarations
void nextFrame();
void showTitle(uint8_t cur);
void moveCursor(uint8_t num);
void nextTitleFrame();
void drawLogo();
void drawTitleMenu();
void drawMenuCursor(uint8_t num);
void showStats();
void nextStatsFrame();
void loadStats();
void saveStats();
void resetStats();
void drawStats();
void drawStatsMenu();
void startPlaying();
void nextPlayFrame();
void nextCorrectFrame();
void nextDeadFrame();
void drawScore();
void drawHangman();
void drawWord();
void drawKeyboard();
void drawCorrect();
void drawDead();
void scoreResponse(char letter);
void pickAWord();
void uart_println(char *str);
extern uint8_t display_frame_count;
void uart_enable();
void uart_disable();
void uart_init();
void uart_print(char *str);
void u32_to_str(char __xdata *str_buf, uint32_t ul);
bool display_next_frame();
bool display_every_x_frames(uint8_t frames);
bool display_next_frame();
3. I will restructure serisman's setup and loop to look like:

Code: Select all

void setup() {
  oscillator_32mhz();
  clock_init();
  ENABLE_INTERRUPTS
  uart_init();
  uart_println("Hello World!");

  display_init();
  display_set_frame_rate(FPS);
}

void loop() {
  uint32_t millis;

// Wait until its time to render our next frame
  if (!display_next_frame())
    return;

// Poll the keypad (disable/enable UART to reduce shared pin conflicts)
  uart_disable();
  keypad_poll();
  uart_enable();

// Send the keypad keymaps to the UART (if it changed)
  if (keypad_changed()) {
    uart_print("keymap: ");
    for (uint8_t i=0; i<4; i++) {
      u8_to_bin_str(str_buf, keypad_get_keymap(i), 5);
      uart_print(str_buf); uart_print(" ");
    }
    uart_println("");
  }

// Send the name of any just pressed/released buttons to the UART
  for (uint8_t col=0; col<4; col++) {
    for (uint8_t row=0; row<8; row++) {
      uint8_t mask = util_bit_to_mask[row];
      if (keypad_just_pressed(col, mask)) {
        uart_print("key pressed: "); uart_println(keypad_get_button_name(col, mask));
      }
      if (keypad_just_released(col, mask)) {
        uart_print("key released: "); uart_println(keypad_get_button_name(col, mask));
      }
    }
  }

// Display Hello World!
  display_set_cursor(3,17);
  display_print("Hello World!");

// 	THE CODE CONTINUES UNTIL THE LASTS }
Essentially that is all of the code changes.

I am using NotePad++ as my editor. We do not have an IDE, so I need to be able to manage my compile, link, binary to Intel HEX formatting. This is the job of a batch file (or if you want, a Makefile.) For demonstration purposes, I will do a three (3) batch files as the concept is far more familiar to most Arduino users:

COMPILE

Code: Select all

REM /-------------------------------------------------COMPILE-----------------------------------------
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 clear_str.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 _delay_loop_8.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 _delay_loop_16.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 _delay_loop_32.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 clock.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 clock_delay_ms.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 clock_long_delay_ms.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 clock_micros.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 clock_millis.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_bitmap.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_char.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_circle.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_fast_hline.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_fast_vline.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_line.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_pixel.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_draw_rect.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_every_x_frames.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_fill_rect.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_get_screen_ptr.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_next_frame.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_print.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_set_cursor.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 display_set_frame_rate.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 eeprom.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 i2c_master.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_any_pressed.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_changed.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_get_button_name.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_get_keymap.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_get_previous_keymap.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_just_pressed.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_just_released.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_poll.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 keypad_pressed.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 reverse_str.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 spi_master.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 str_to_str.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 u8_to_bin_str.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 u8_to_str.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 u32_to_str.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 uart.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 uart_print.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 uart_println.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 uart_put_char.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 uc1701.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 util_bit_to_mask.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 util_mask_to_bit.c
sdcc -mmcs51 -c --std-sdcc11 --opt-code-size -DCC2533 -DF_CPU=32000000 main.c


LINK

Code: Select all

sdcc -mmcs51 --xram-loc 0x0000 --xram-size 0x0F00 main.rel clock_millis.rel display.rel display_draw_bitmap.rel display_print.rel display_set_cursor.rel display_set_frame_rate.rel keypad_any_pressed.rel keypad_changed.rel keypad_get_button_name.rel keypad_get_keymap.rel keypad_just_pressed.rel keypad_just_released.rel keypad_poll.rel keypad_pressed.rel u8_to_bin_str.rel uc1701.rel util_bit_to_mask.rel display_draw_char.rel display_get_screen_ptr.rel keypad_get_previous_keymap.rel util_mask_to_bit.rel keypad.rel clock.rel clock_delay_ms.rel clock_long_delay_ms.rel clock_micros.rel _delay_loop_16.rel spi_master.rel  u8_to_str.rel display_fill_rect.rel display_draw_line.rel display_draw_fast_vline.rel str_to_str.rel display_draw_pixel.rel reverse_str.rel display_every_x_frames.rel display_draw_circle.rel display_draw_fast_hline.rel clear_str.rel eeprom.rel i2c_master.rel _delay_loop_8.rel display_next_frame.rel uart.rel uart_print.rel uart_println.rel uart_put_char.rel u32_to_str.rel 

CONVERT

Code: Select all

packihx main.ihx >Hello-World.hex

SUMMARY

My total cost investment was $10 U.S.D. $2 for the SMART Response PE unit from eBay and $8 for the CC Debugger clone.

I have shown how convoluted C code for old non-Arduino hardware can be utilized and reprogrammed without radically changing your Arduino mindset.
To put this in prospective, the converted unit is battery powered, has a keyboard option, has a rudimentary LCD display, and has a very convenient carrying case ... no 3D printing required.

What do I intend to do with this thing? With 2x the UNO SRAM and 40K of flash left over and 1K of eeprom, surely I can find something to do productive. Or, maybe the endgame is just the satisfaction to hacking this old device until I own it. Anyway, it has been a rainy day and I am satisfied with my efforts.

Ray
Attachments
Hello-World.zip
(43.7 KiB) Downloaded 169 times
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Repurpose a CC2533 hardware and code Arduino-ish

Post by ag123 »

+1
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: Repurpose a CC2533 hardware and code Arduino-ish

Post by mrburnette »

One of the Arduino-ish things I like to do is to set up inside the loop() {} section a set if straight-forward calls to functions. This makes for both readable code and efficient maintainable code.

Today I tackled the clicker keyboard. The core code by serisman uses a double-matrix to handle key closures as a row-column pair and stores the x, y in separate arrays. Thus, in the main program, a nested set of for loops scans the arrays and the results is the row and column numbers. This is not directly useful unless we employ nested switch statements ... not pretty. However, with a small number of keys, we can employ a bit of trickery and generate a single integer to uniquely identify each key: just multiply the row value by 5 and add the column value to create a non-continuous keymap which is unique. The Results of the math yields:

Code: Select all

switch (Results) {
case 0: // Enter
       // function();
       break;
case 1: // Yes/Checkmark
       // function();
       break;
case 2: // No/Xcross
       // function();
       break;
case 3: // del/Backspace
       // function();
       break;
case 5: // ?/Help
       // function();
       break;
case 6: // A/1
       // function();      
       break;
case 7: // B/2
       // function();
       break;
case 8: // C/3
       // function();
       break;      
case 10: // Menu/Home
       // function();
       break;
case 11: // D/4
       // function();
       break;
case 12: // E/5
       // function();
       break;
case 13: // F/6
       // function();
       break;
case 15: // Up
       // function();
     break;      
case 16: // G/7
       // function();
       break;
case 17: // H/8
       // function();
       break;
case 18: // I/9
       // function();
       break;
case 20: // Down
       // function();
       break;
case 21: // +/-
       // function();
       break;
case 22: // J/0
       // function();
       break;
case 23: // x-y/.
       // function();
       break;
case 35: // Power
       // function();
       break;
default:
       break;
}
Using this trick, any keystroke can call a function. Simply edit the representative line identified as "// function();" and replace that with your own function_name();

All the keys can be active, or just one. Simple.

Ray
mrburnette
Posts: 633
Joined: Thu Dec 19, 2019 1:23 am
Answers: 7

Re: Repurpose a CC2533 hardware and code Arduino-ish

Post by mrburnette »

2021-09-20 Update

I have been having lots of fun with SDCC and the CC2533 uC that is in the Smart Response PE remote.

My 8 YO grandson was delighted with the Hangman Game that I slightly "modified" so the opening screen showed his name! I even put a cheat key in the S/W so the daughter can take the unit and help the grandson out with really difficult problems :shock:
99.9% of the code was previously concocted by Serisman here Hangman for CC2533

But, there is only so much for Hangman and at my age I really do not strive to spell, spellchecker does it for me.

So, I thought about something that would be fun to write. I came up with a RPN calculator, the pictures show the implementation.
RPN Resized.jpg
RPN Resized.jpg (27.14 KiB) Viewed 1906 times
The code is not particularly interesting, certainly not sophisticated, but the worker part of the loop() is this function that deals with all of the major tasks:

Code: Select all

void nextFrame() {
	keypad_poll();						// Poll the keypad
	if (keypad_any_pressed())
	{
		// display_set_cursor(3,8);		// (# Pixels down, # Pixels right) all referenced to (0,0) top-left corner
		for (uint8_t col=0; col<4; col++) {
		  for (uint8_t row=0; row<8; row++) {
			uint8_t mask = util_bit_to_mask[row];
			if (keypad_pressed(col, mask)) {
			  uint32_t Results = (uint32_t)(row * 5 + col);
			
			  switch (Results)
				{
				case 0:					// Enter);  different behavior if display is == 0 or != 0
					displayShow();
					if(Tmp_reg != 0) PolishStackPush(); 
					DoTheMath();
					Tmp_reg = 0; displayZero();
					break;
				case 1:					// Lf arrow
					StackRoll();
					break;
				case 2:					// Rt arrow can act as ENTER if non=zero value
					PolishStackPush();
					displayZero(); 
					if (Tmp_reg > 0) Tmp_reg = 0;
					break;
				case 3:					// del/Backspace
					if (decade > 0) {
						moveDigitsLeft();
						decade = decade--;
						digits[decade] = 0;
					}
					break;
				case 5:					// ?/Help
					timeSincePwrOn(30, 40);
					break;
				case 6:					// A/1
					if (l_more) {moveDigitsRight(); digits[0] = 1; ++decade;}
					break;
				case 7:					// B/2
					if (l_more) {moveDigitsRight(); digits[0] = 2; ++decade;}
					break;
				case 8:					// C/3
					if (l_more) {moveDigitsRight(); digits[0] = 3; ++decade;}
					break;
				case 10:				// Menu/Home == Clear the digit buffer and Tmp value
					displayZero();
					break;
				case 11:				// D/4
					if (l_more) {moveDigitsRight(); digits[0] = 4; ++decade;}
					break;
				case 12:				// E/5
					if (l_more) {moveDigitsRight(); digits[0] = 5; ++decade;}
					break;
				case 13:				// F/6
					if (l_more) {moveDigitsRight(); digits[0] = 6; ++decade;}
					break;
				case 15:				// Up
					DoDefault++; if (DoDefault > 3) DoDefault = 0;
					break;
				case 16:				// G/7
					if (l_more) moveDigitsRight(); digits[0] = 7; ++decade;
					break;
				case 17:				// H/8
					if (l_more) moveDigitsRight(); digits[0] = 8; ++decade;;
					break;
				case 18:				// I/9
					if (l_more) {moveDigitsRight(); digits[0] = 9; ++decade;}
					break;
				case 20:				// Down
					if (DoDefault == 0) {
						DoDefault = 3;	// roll-over
					} else {
						DoDefault--;
					}
					break;
				case 21:				// +/-;
					break;
				case 22:				// J/0
					if (l_more) {moveDigitsRight(); digits[0] = 0; ++decade;}
					break;
				case 23:				// x-y/.
					Tmp_reg = X_reg; X_reg = Y_reg; Y_reg = Tmp_reg;
					break;
				case 35:				// Power
					break;
				default:
					break;
				}
			}
		  }
		}
		clock_delay_ms(150);			// elastomer keyboard kind of sucks
	}
	displayShow(); 	displayMathOp();	
	display_paint(true);				// in Display.h macro: inline void display_paint(bool clear)   { uc1701_paint(screen, clear); }	
}
keystrokes are gathered into the

Code: Select all

char		__xdata str_buf[12];
and then the characters are turned into a a set of 4 registers, X, Y, Z, T

Code: Select all

float    	__xdata X_reg = 0;			// X, Y, Z, T like on a reverse-polish HP
float    	__xdata Y_reg = 0;
float    	__xdata Z_reg = 0;
float    	__xdata T_reg = 0;
Many thanks to Serisman who does Arduboy stuff for the CC2533 code, much recasted from the open source TI toolkit: RemoTI-CC253xDK-1.3.1
20210920 RPN resize.png
20210920 RPN resize.png (80.82 KiB) Viewed 1905 times
SDCC does an OK job... the binary (Intel HEX) is 27K of the 64KB of flash available on this rather long-in-the-tooth uC.
Post Reply

Return to “Off topic”