Jump to content
Sign in to follow this  
spirilis

My time with the Renesas RX

Recommended Posts

Since I got the RX62N demo board mentioned in the other thread (viewtopic.php?f=33&t=3109) ... I decided it's time to do this shit. Get my feet wet and start the journey. (I also got the Stellaris LaunchPad, geez, too many complicated 32-bit toys to play with!!)

 

Edit: Highly recommend RX newcomers hit up this document: http://renesasrulz.com/renesas_products/rx/m/mediagallery/140.aspx

Very quickly gets you up to speed with some of the high-level concepts in the chip's hardware that you may bang your head against.  Further detail is found in the 2000-page Hardware User's Manual.

 

 


I'm just going to dump my thoughts and processes in here so maybe RX n00bs can follow the footsteps (like a trained monkey) and get something out of it... or at least get their foot in the door.

Ok, so first entry. What have I done so far-
1. Installed HEW, SEGGER J-Link drivers from the CD. I don't have GNURX on my Windows netbook yet but the Renesas compiler still has 50 days left on its eval.
2. Started HEW, created a new application project, no frills

What it's provided me is a project with a crapton of pre-populated .c and .h files:
Test1_LeftPane.png

TBH this confused me quite a bit at first, but I have an idea why it produces so many. Iodefine.h is basically your processor-specific I/O register manifest, like the and requisite msp430g2553.h, msp430fr5739.h, etc. that MSPGCC et al use. In Renesas HEW land, this .h file is included in your project.

Most of the other .c files provide basic stuff that you might want to customize--intprg.c defines all the Interrupt Vectors, so when you want to change it you go in there, find the interrupt vector you want to change and toss your code in its place. Sounds like a lot of project "sugar" to me--to throw everything out there for professionals who want the rusty innards mapped out already in .c and .h files.

The only one I care about right now though, is Test1.c, the designated home of main().

The default Test1.c has some C++ #ifdef's for some reason but since I didn't care, I pared it all down to just this:

/***********************************************************************/
/* */
/* FILE :Test1.c */
/* DATE :Sat, Sep 29, 2012 */
/* DESCRIPTION :Main Program */
/* CPU TYPE :RX62N */
/* */
/* This file is generated by Renesas Project Generator (Ver.4.53). */
/* NOTE:THIS IS A TYPICAL EXAMPLE. */
/* */
/***********************************************************************/

#include "iodefine.h"

void main(void)
{

PORTD.DDR.BIT.B5 = 1; // PD5 = Output
PORTD.DR.BIT.B5 = 0; // DR = Output register
while(1) ;

}


Note that #include "iodefine.h" isn't put in there by default, you have to add that or else the PORT* SFR structs & unions won't exist and the compiler will throw an error.

I wanted to light up an LED so I got the port ID by:
1. Looking at the YRDKRX62N user manual, found by going Start->All Programs->Renesas->YRDKRX62N->User manual (at the bottom), in chapter 6 it talks about the "user circuitry" on the board, 6.3 explains the LEDs. I don't like how they don't tell you the I/O ports in there, just the "LED4", "LED5" etc. labels on the silkscreen, but they do explain that LED4 is MCU pin#81.
2. Resolve MCU pin#81 to the requisite PORT -- open the RX62N series Hardware Manual, found in that same folder in the Start menu. Section 1.4 has the pinout for the 100-pin LQFP chip, which is what this board contains--pin 81 is PD5, aka PORTD5.

From perusing some of that college textbook by Dr. James Conrad which uses this chip, I recall seeing that I/O ports are referenced with a struct of unions, e.g. PORTD.DR.BIT.B5 = 1 sets a single bit in the DR (output data) register, but PORTD.DR.BYTE = 0x20 would achieve the same thing (and set everything else in that port to 0). There's a PORTD.DDR, PORTD.DR, PORTD.PORT that we care about; DR is the output, PORT is the input, DDR sets the direction for the port.

I'm guessing the LEDs on this board have their anodes connected to +Vcc and the cathodes connect to the RX62N processor, hence why setting the DR bit to "0" lights it up (I tried "1" first and that didn't work.)

After plugging in the USB Mini cable to the SEGGER J-Link Lite onboard, go to Debug->Debug Sessions, set the Current session to the SEGGER one, tell it the right parameters (this is an RX62N processor, EXTAL is running at 12MHz btw; CPU runs at 96MHz, I think that's to maintain proper clocking for the USB host/OTG/device peripheral) and get it going.

Be sure to "Connect" to the debugging session (check near the bottom of the Debug menu) if it's not already connected, then from the Build menu, select "Build All". This should compile everything--including doing a custom recompile of the standard C library to account for any user-configured changes like altered compiler optimization, Endianness (yes this CPU can run Little-Endian OR Big-Endian, it's your choice), etc. It'll finally give you the option to upload the code to the board, hit Yes, then once it's done, from the Debug menu hit Reset-Go.

With the code I posted above, LED4 (in the motor-looking ring of LEDs on the demo board) lights up green near the top of the ring.

Next task: Figure out the Timers, and get this baby blinking!

Share this post


Link to post
Share on other sites

Spending a few minutes with this board ... just because I can, I guess.

 

Installed GNURX v12.02 since I have 16 days left on the Renesas RX compiler eval, got my LED on program running in there. I actually prefer the way the source files get organized in HEW with GNURX's project generator, I think it names them better for one.

 

Finding the various SFR registers in the Hardware manual is one thing, locating their C equivalent entails searching through iodefine.h. The key seems to be, find the register name, scroll backwards to find the struct declaration--e.g. for SCKCR (system clock control register) it is under the struct st_system:


struct st_system {
....
 union {
   unsigned long LONG;
   struct {
     unsigned long :4;
     unsigned long ICK:4;
     unsigned long PSTOP1:1;
     unsigned long PSTOP0:1;
     unsigned long :2;
     unsigned long BCK:4;
     unsigned long :4;
     unsigned long PCK:4;
   } BIT;
 } SCKCR;
....
};

 

But referencing SCKCR doesn't work, so take its parent struct (struct st_system) and locate it at the end of the file:


#define SYSTEM (*(volatile struct st_system *)0x80000)

 

You can then modify SCKCR's values using SYSTEM.SCKCR, like:

// ICK configures the Instruction Clock (ICLK), i.e. the main CPU clock.
SYSTEM.SCKCR.BIT.ICK = 0x00; // ICK = 0b0000 means FLL=x8, ICLK=EXTAL*8 (12MHz * 8 = 96MHz, full speed)

 

As far as PWM'ing the LEDs, looks like the LEDs on the RDK board do not correspond to pins with Output Compare Match capability, so the best I can do is set up a timer and blink them (or PWM in software, I suppose).... Still working on that one.

Share this post


Link to post
Share on other sites

Bravo... Got an LED blinking. The interrupt system on these chips is crazy. (At least compared to the MSP430, but you'd expect that anyhow, wonder how the Stellaris is in comparison...)

 

To activate an interrupt you need to do 3 things:

1. Clear the interrupt bit in case it was set previously, using the IR(x,y) macro, and the 2 parameters inside there you may have to look up in iodefine.h near the end--e.g. for the 8-bit Timer 0's compare match A IRQ, it was:

#define IEN_TMR0_CMIA0 IEN6

so the two parameters you use for the IRQ macros are TMR0, CMIA0.

 

2. Activate the interrupt in the peripheral module itself

3. Set an Interrupt Priority for the IRQ; default is 0, which disables it, I set mine to 2 and it worked. 1 would have worked too.

Kinda frustrating when you're enabling the interrupts and wondering ...... why isn't this firing? Anyway it's probably a good idea to keep a copy of that iodefine.h and study the bottom part a bit so you know what the names of the different modules' various interrupt sources are in the macro form.

 

So here's what I did:

1. The chip has four 8-bit timers, you can combine the 2 pairs into 16-bit timers by setting the clock source of one to be cascaded from the other, interrupts work properly this way too. I combined TMR0+TMR1, set its clock at PCLK/8192 (maximum clock divider) and enabled Clear on Compare Match A + Interrupt on Compare Match A.

 

Another gotcha is the various modules are powered off by default, and there are various MSTP* registers to control the on/off state of these modules. Again, iodefine.h has macros for making this nicer.

 

So we start with hardware_setup.c, one of the ancillary C source files it generates; it contains a single function "void HardwareSetup(void)" that gets run before main() with some default SCI (UART) settings prepopulated but commented out.

I make it look like this:


void HardwareSetup(void)
{
   SYSTEM.SCKCR.BIT.ICK = 0x00;  // ICLK = EXTAL * 8 (96MHz)
   SYSTEM.SCKCR.BIT.PSTOP0 = 1;  // Disable SDCLK
   SYSTEM.SCKCR.BIT.PSTOP1 = 1;  // Disable BCLK
   SYSTEM.SCKCR.BIT.PCK = 0x02;  // PCLK = EXTAL*2 (24MHz)

   MSTP(TMR0) = 0;  // Power-on TMR0
   MSTP(TMR1) = 0;  // Power-on TMR1
}

 

Then in main(), I set up the LEDs and create a separate function to toggle the LED in question:

 

int main(void)
{
   PORT2.DDR.BIT.B1 = 1;
   PORT2.DR.BIT.B1 = 0;    // Shut off that distracting LCD's backlight

   PORTD.DDR.BIT.B5 = 1;   // PD5 LED = Output pin
   PORTD.DR.BIT.B5 = 1;    // PD5 LED = OFF

   TMR0.TCCR.BIT.CSS = 0x03;  // 16-bit mode
   TMR0.TCCR.BIT.CKS = 0x00;
   TMR1.TCCR.BIT.CSS = 0x01;
   TMR1.TCCR.BIT.CKS = 0x06;  // Timer = PCLK/8192 (2929 ticks/second @ 24MHz)

   TMR0.TCR.BIT.CCLR = 0x01;  // Reset counter at Compare Match A
   TMR0.TCR.BIT.CMIEA = 1;    // Enable Interrupt on Compare Match A inside the peripheral module
   IR(TMR0,CMIA0) = 0;    // Clear IRQ if it was on for some reason
   IPR(TMR0,CMIA0) = 2;  // IRQ priority for TMR0.CMIA0 = 2
   IEN(TMR0,CMIA0) = 1;  // Enable TMR0.CMIA0 IRQ in the Interrupt Control Unit

   TMR01.TCORA = 2000;    // Compare match at TCNT=2000

   while (1)
       ;
   return 0;
}

void led_toggle()
{
   if (PORTD.DR.BIT.B5)
       PORTD.DR.BIT.B5 = 0;
   else
       PORTD.DR.BIT.B5 = 1;
}

 

The led_toggle function I prototyped inside a "main.h" I created, then made sure both the main program (LED_BLINK.c) and the Interrupt Handlers (interrupt_handlers.c) included it.

 

Then in interrupt_handlers.c, I hunted for something TMR0 / CMIA0 related and found:


//;0x02B8  TMR0_CMI0A
void  INT_Excep_TMR0_CMIA0(void){ } 

 

Changed it to:


//;0x02B8  TMR0_CMI0A
void  INT_Excep_TMR0_CMIA0(void){ led_toggle(); } 

 

After that, saved everything, did Build>Build All (it asks you at the end if you'd like to flash the binary to the chip), then hit Go and voila... blinking once every (just under 1) second.

Share this post


Link to post
Share on other sites

Also fyi, the if() statement in led_toggle wasn't necessary, just using a "PORTD.DR.BIT.B5 ^= 1" works fine (tested it just now) ... that was just some craziness I did when I couldn't figure out why it wasn't working.

 

Another thing to note is the "TMR01.TCORA" nomenclature... they're normally TMR0, TMR1, TMR2, TMR3 but when combining them into 16-bit pairs it's TMR01 and TMR23 for the TCORA/TCNT/etc. registers.

Share this post


Link to post
Share on other sites

I noticed when building Stellaris programs by hand, the "startup_gcc.c" file you have to include in the compilation serves a very similar purpose to Renesas' various vector_table.c, interrupt_vectors.c, etc. stuff.

 

Guess that's a typical thing you find with higher-end processors eh?

 

Given that I've got my Stellaris GCC toolchain working under my Mac, not sure how much time I'll spend on this, but eh... Maybe I'll try my hand at building GNURX on the Mac, I've heard it's possible and there is a USB bootloader for uploading new code to the RX anyhow.

Share this post


Link to post
Share on other sites

Alright, I think what I need to do is start setting some goals so I can keep pace with learning this thing.

 

So here's my "resolution": Learn one peripheral a week.

 

Learned how to twiddle I/O ports, learned how the 8/16-bit timer works, now I am coming up with a list of peripherals and prioritize them into a list.

Share this post


Link to post
Share on other sites

Renesas RX - RX62N peripherals + learning objectives (LQFP-100 version on the YRDK board)

I/O port - Input
I/O port - Output
TMR Timers - 8/16-bits (4x 8-bit or 2x 16-bit when cascading the pairs)
Watchdog Timer
Independent Watchdog Timer
Data Flash - 32KB
I/O port interrupts

12-bit ADC
10-bit ADC
1-channel 10-bit DAC

RSPI (Serial Peripheral Interface)
SCI Serial Communications Interface (UART, SmartCard)
I2C Bus

Compare Match Timer
Multi-function Timer Pulse Unit
Programmable Pulse Generator

DMA controller
Data Transfer controller

Sleep modes
Realtime Clock

USB 2.0 Device Mode
USB 2.0 Host Mode

Ethernet MAC
CAN bus
External Bus

Share this post


Link to post
Share on other sites

And on another thought, apparently you can buy the RX62N processors: http://octopart.com/partsearch#search/requestData&q=r5f562n

 

The one on the RDK is the top of the line, 512KB flash/96KB SRAM (R5F562N8BDFP for LQFP-100), but they're all 0.5mm pitch (however most chips are when they're that big). Not that cheap but considering what they come packed with... although for Ethernet you need to add PHY hardware (including signalling IC, the RX62N only comes with MAC controller).

Share this post


Link to post
Share on other sites

Ok, had to knock this one out really quick -- I/O Input

 

Using the board's volume control potentiometer as the input, reading it digitally rather than with the ADC (it's also AN4), I can flip one of the red LEDs on (after turning volume control above half) or off (turning it below half):

 

hardware_setup.c (clock init)


void HardwareSetup(void)
{
   SYSTEM.SCKCR.BIT.ICK = 0x00;  // ICLK = 96MHz
   SYSTEM.SCKCR.BIT.PCK = 0x02;  // PCLK = 24MHz
   SYSTEM.SCKCR.BIT.PSTOP1 = 1;
   SYSTEM.SCKCR.BIT.PSTOP0 = 1;
}

 

ioblink.c (main program)


int main(void)
{
   PORT2.DDR.BIT.B1 = 1;
   PORT2.DR.BIT.B1 = 0;   // Shut off that distracting LCD backlight

   PORTD.DDR.BIT.B1 = 1;
   PORTD.DR.BIT.B1 = 1;   // PD1 = OFF

   // Initialize our input pin -- AN4 (P44, potentiometer)
   PORT4.DDR.BIT.B4 = 0;
   PORT4.ICR.BIT.B4 = 1;  // Input buffer enabled

   // Tight loop - Monitor state of PORT4, reflect output on PD1.
   while (1) {
       PORTD.DR.BIT.B1 = !PORT4.PORT.BIT.B4;
   }

   return 0;
}

 

An interesting step here is that the Input Buffer is a device that can be switched off, so you have to turn it on to properly receive digital input.

Share this post


Link to post
Share on other sites

Getting cozier with their new Eclipse-based e2studio, and found a good time saver--the left pane lets you expand header files and surf their contents:

post-15991-0-89133200-1354067801_thumb.png

 

Scrolling down, expanding the un_wdt union:

post-15991-0-59953600-1354067809_thumb.png

 

 

So far it looks like there are 2 WDT's, one clocked by PCLK and one clocked by its own (probably low-power) slower ~125KHz clock. The main WDT (PCLK-based) has some convoluted way of writing to the registers, you write to the WINA and WINB with different passwords in the upper 8 bits depending on which WDT register you want to write to. Studying up on that some more.

Share this post


Link to post
Share on other sites

Ok, WDT example:

 

Setting up TMR0+1 to do an overflow interrupt that toggles one of the LEDs, increments a global variable and the main function waits until that global has incremented to 20, then activates the WDT in full reset mode and goes into a while(1) ; loop.

I see the red LED flash several times and then a quick flicker of the onboard LCD display's backlight--indicating a reset, since the backlight turns on by default after reset (and is quickly switched off by this app).

 

First, hardware_setup.c:


void HardwareSetup(void)
{
  SYSTEM.SCKCR.BIT.ICK = 0x00;  // ICLK = 96MHz
  SYSTEM.SCKCR.BIT.PCK = 0x02;  // PCLK = 24MHz
  SYSTEM.SCKCR.BIT.PSTOP1 = 1;
  SYSTEM.SCKCR.BIT.PSTOP0 = 1;

  MSTP(TMR0) = 0;
  MSTP(TMR1) = 0;

  TMR0.TCCR.BIT.CSS = 0x03;  // 16-bit mode
  TMR1.TCCR.BIT.CSS = 0x01;
  TMR1.TCCR.BIT.CKS = 0x04;  // Timer = PCLK / 64
  TMR0.TCR.BIT.CCLR = 0x00;  // No explicit reset
  TMR0.TCR.BIT.OVIE = 1;     // Enable Overflow Interrupt
  IR(TMR0, OVI0) = 0;
  IPR(TMR0, OVI0) = 1;
  IEN(TMR0, OVI0) = 1;
  // ^ Enable TMR0 Overflow Interrupt

  /* Initialize PD6 */
  PORTD.DDR.BIT.B6 = 1; // Output
  PORTD.DR.BIT.B6 = 1;  // Off initially

  // Shut off that distracting LCD backlight
   PORT2.DDR.BIT.B1 = 1;
   PORT2.DR.BIT.B1 = 0;
}

 

The ISR for TMR0's OVI0 (overflow interrupt) looks like this in interrupt_handlers.c:


#include "wdtreboot.h"
void  INT_Excep_TMR0_OVI0(void){
   PORTD.DR.BIT.B6 ^= 1;
   tmrovf++;
}

 

The wdtreboot.h just declares the extern 'tmrovf' variable:


#ifndef WDTREBOOT_H_
#define WDTREBOOT_H_

extern unsigned int tmrovf;


#endif /* WDTREBOOT_H_ */

 

And last but not least, the main program (wdtreboot.c):


int main(void)
{
  tmrovf = 0;

  while (tmrovf < 20)
     ;

  IEN(TMR0, OVI0) = 0;  // Disable TMR0 Overflow Interrupt

  WDT.WRITE.WINA = 0xA500 | 0x0098 | 0x40 | 0x20 | 0x03;  // Watchdog Mode, Timer Enable, WDT=PCLK/131072
  WDT.WRITE.WINB = 0x5A00 | 0x001F | 0x40;  // Reset Enable

  while(1)
     ;
   return 0;
}

The extraneous 16-bit integers for WINA/WINB include the Password byte in the upper 8 bits and the Reserved bits, some of which must be set to 1 according to the RX62N, RX621 Group Hardware User's Manual. The 8-bit hex you see is the actual WDT register values.

Share this post


Link to post
Share on other sites

Hm, so one thing I looked at in terms of cost & features is ethernet support--apparently these Renesas RX chips that do have ethernet only have MAC support, not PHY, and the PHY transceiver they use on the demo board (TI/National DP83640) costs more than the damned RX chip itself. Probably a ~$22 outlay to buy an RX62N + PHY transceiver, whereas by comparison TI's Stellaris LM3S6965 only costs around $13 in single qty and has PHY directly on the chip.

 

OTOH, I don't see any references to a dedicated ethernet DMA controller on the LM3S like there is on the RX62N, the flash runs slower than the CPU (RX has true 100MHz zero-wait-state flash), the renesas is more comparable to a Cortex-M4F type of chip and runs faster. But it doesn't sound like a low-cost way of obtaining embedded ethernet by any means. I'm guessing as TI expands the new LM4F line to include ethernet support (and I'm assuming they are...) this gap in cost will be more significant.

Share this post


Link to post
Share on other sites

Also looks like KPIT Cummins released a new "v12.03" of the GNURX toolchain on 11/23... Installed on my netbook, seems to work correctly. Might just be me but the tools seem to execute a little faster during the build process.

Share this post


Link to post
Share on other sites

Got an IWDT example going. The IWDT isn't as interesting as the WDT; while it does run off its own clock source, it is not flexible at all, there is no "interval" mode interrupt and it can only be configured once after reset--then refreshed as often as need be. So more like a watchdog that just happens to use a separate clock source in case the main clocking system takes a dump.

 

Similar to the WDT example above, we set up TMR0+1 as 16-bit, blink an LED 20 times, then wait another 10 cycles of that (without executing the ISR, just polling the interrupt flag) before starting the watchdog.

 

hardware_setup.c


void HardwareSetup(void)
{
   SYSTEM.SCKCR.BIT.ICK = 0x00;  // ICLK = 96MHz
   SYSTEM.SCKCR.BIT.PCK = 0x02;  // PCLK = 24MHz
   SYSTEM.SCKCR.BIT.PSTOP1 = 1;
   SYSTEM.SCKCR.BIT.PSTOP0 = 1;

   MSTP(TMR0) = 0;
   MSTP(TMR1) = 0;

   TMR0.TCCR.BIT.CSS = 0x03;  // 16-bit mode
   TMR1.TCCR.BIT.CSS = 0x01;
   TMR1.TCCR.BIT.CKS = 0x04;  // Timer = PCLK / 64
   TMR0.TCR.BIT.CCLR = 0x00;  // No explicit reset
   TMR0.TCR.BIT.OVIE = 1;     // Enable Overflow Interrupt
   IR(TMR0, OVI0) = 0;
   IPR(TMR0, OVI0) = 1;
   IEN(TMR0, OVI0) = 1;
   // ^ Enable TMR0 Overflow Interrupt

   /* Initialize PD6 */
   PORTD.DDR.BIT.B6 = 1; // Output
   PORTD.DR.BIT.B6 = 1;  // Off initially

   // Shut off that distracting LCD backlight
   PORT2.DDR.BIT.B1 = 1;
   PORT2.DR.BIT.B1 = 0;

}

 

iwdtreboot.h (tmrovf extern unsigned int)


#ifndef IWDTREBOOT_H_
#define IWDTREBOOT_H_

extern unsigned int tmrovf;

#endif /* IWDTREBOOT_H_ */

 

interrupt_handlers.c for TMR0 Overflow ISR


//;0x02C0  TMR0_OV0I
#include "iwdtreboot.h"
#include "iodefine.h"
void  INT_Excep_TMR0_OVI0(void){
   PORTD.DR.BIT.B6 ^= 1;
   tmrovf++;
}

 

And last, the main program:

unsigned int tmrovf;


int main(void)
{
   int i;

   tmrovf = 0;

   while (tmrovf < 20)
       ;

   IEN(TMR0, OVI0) = 0;  // Disable TMR0 Overflow Interrupt
   PORTD.DR.BIT.B6 = 1;  // Switch off LED
   IR(TMR0, OVI0) = 0;
   for (i=0; i<10; i++) {
       while (!IR(TMR0, OVI0))  // But wait 10 more cycles of the TMR overflow before starting the WDT-
           ;
       IR(TMR0, OVI0) = 0;  // Clear interrupt
   }
   //IWDT.IWDTCR.BIT.CKS = 0x80;  // Clock = IWDTCLK/256
   //IWDT.IWDTCR.BIT.TOPS = 0x03; // Timeout in 16384 cycles
   IWDT.IWDTCR.WORD = 0x3300 | (0x80 << 4) | 0x03;  // Clock = IWDTCLK/256, Timeout in 16384 cycles

   // Start IWDT
   IWDT.IWDTRR = 0x00;
   IWDT.IWDTRR = 0xFF;

   while(1)
       ;
   return 0;
}

 

You can only write to IWDTCR once after reset, and that means you need to write the whole WORD with everything packed in. Then resetting the IWDT involves writing 0x00 followed by 0xFF to IWDT.IWDTRR; first time it starts the clock, every time after it just resets it.

 

Similar to before, a red LED blinks a few times but unlike the previous example I have this one stop for a short while, then the onboard LCD backlight flickers due to the reset.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×