NXJ + Hume: Building on the platform codebase

Post your NXJ projects, project ideas, etc here!

Moderators: 99jonathan, roger, imaqine

NXJ + Hume: Building on the platform codebase

Postby CoBB » Tue Apr 24, 2007 12:51 pm

Hello everyone,

I'm trying to port a language called Hume to the NXT, and since I'm mainly interested in this language, I'd like to take the lowest layer of leJOS to avoid having to reimplement peripheral handling. Unfortunately I'm not familiar with ARM development, let alone NXT hardware, and I'm running into certain problems I can't solve with fast hacks.

So far what I did was taking the platform/nxt directory, cutting all references to the VM and calling xx_show() to test the core functions. It worked well, so I took my own, apparently well-working program, which sat on top of a little bit of LCD display code yanked from the firmware, and tried to glue it to the leJOS core. The only functions I called were the ones used in xx_show(): display_*() and systick_wait_ms(). However, it simply didn't work. The symptoms were mind-boggling: data aborts at random times, consistently raised somwhere in i2c_timer_isr_C().

I started looking around a bit, and the only possible point of interference I saw was display_update(), more precisely nxt_spi_write(). Since the ISR writes to *AT91C_PIOA_{S,C}ODR, I decided to move their initialisation code inside the loop, so they are set for every byte sent. This seemed to solve the problem momentarily, but as soon as I changed my program a bit, data aborts returned. After this, I found that putting a little delay after each display update helps, but needless to say, I'm not really satisfied with such a fragile hack...

What's the real solution? What rules should I observe while using the core functions in order to avoid such conflicts?
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby CoBB » Sun Apr 29, 2007 6:14 pm

I’d really appreciate some help on this matter.

I’ve been digging around in the JVM code to find a solution, but it seems to me that display_update() is called without taking any extra measures. (Correct me if I’m wrong.) Does that never cause any problem?

For the time being I ‘solved’ this issue by disabling interrupts during each LCD update, but this is obviously another hack that doesn’t feel right at all.
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby lawrie » Tue May 01, 2007 6:28 pm

Are you running your code from flash memory - i.e are you using the ROM build of lejos? If so, I have just fixed a problem in init.s with very similar symptoms to the ones you are getting. It is in SVN. The wait states for flash memory were not set correctly. We have only just started using the flash version of lejos - the released alpha versions download the code using SAMBA and run it in RAM. They do not hit this problem.
lawrie
leJOS Team Member
 
Posts: 909
Joined: Mon Feb 05, 2007 1:27 pm

Postby CoBB » Tue May 01, 2007 8:34 pm

Precisely, it’s the ROM build. Thanks for the fix, I’ll try it soon.
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby CoBB » Fri May 11, 2007 1:03 pm

Well, it seems that the fix worked, thanks for that. On the other hand, now the RAM version gives a data abort immediately after the splash screen. I just tried the View test right after a fresh checkout.
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby lawrie » Fri May 11, 2007 1:55 pm

The SVN version has changed to support a start-up menu read from flash memory. You need to build libnxt and then do:

nxjflash lejos_nxt_rom.bin StartUpText.bin

This will flash the VM and the start-up menu. After that you can put the NXT back in firmware update mode and run the RAM version, if you like.

If you don't flash a start up menu, it will read random data from flash memory, which is probably what you are experiencing.

We have a current problem that the flash version works on some NXTs but not others.
lawrie
leJOS Team Member
 
Posts: 909
Joined: Mon Feb 05, 2007 1:27 pm

Postby CoBB » Mon May 14, 2007 11:06 am

No matter what I do, both the execute and delete items say the following:

Code: Select all
Java Exception:
Class: 8
Method: 0

This is a NullPointerException, right?

If I upload a menu, using the command from the readme to execute the View example doesn't seem to do anything other than starting up the menu again with the same problem repeated. 'nxjupload View.bin' gives me this answer:

Code: Select all
Error receiving reply from OPEN WRITE: USB read error

I still see the name of the file in the menu, but trying to execute or delete it results in a data abort.

On another note, while playing around with this, I found that something is bogus with fwflash in the SVN version, because it can't upload the factory firmware properly; it seems to leave out some additional files like sounds or the demo program, and the on-brick programming function is also broken (programs can't be executed). At the same time, the older version used in the nxtgcc project doesn't have this problem. This might be an issue that affects everything in libnxt. Or is this something to be expected?
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby lawrie » Wed May 16, 2007 9:23 am

Are you running the rom or samba ram version when you get these problems with the menu?

If it is the flash version, I mentioned that the current version seems to work on some NXTs and not others. I am working on this, but as it works on my NXT, it is hard to diagnose.

I don't know what is wrong with fwflash. I have not knowingly made any changes to it, but I do not use it for flashing the standard firmware, and I don't think anyone else does.

You will get quicker replies if you mail me directly at lawrie.griffiths@ntlworld.com.
lawrie
leJOS Team Member
 
Posts: 909
Joined: Mon Feb 05, 2007 1:27 pm

Postby CoBB » Fri Jun 01, 2007 1:35 pm

Thanks for the replies. I was distracted lately by other, more urgent activities, so I couldn't react earlier. Now I checked out the latest version, and it seems to work well the following way:

1. Reset.
2. Flashing the menu by saying "nxjflash lejos.bin StartUpText.bin", where lejos.bin is a copy of a freshly built lejos_nxt_rom.bin right after checkout.
3. Reset.
4. Uploading a custom firmware with runc (I quickly rebuilt the current one with xx_show() to test it).

Step 4 can be repeated any number of times by simply removing the batteries, so no need for more hard resets. Great work, guys! :)

By the way, in libnxt/flash_write/Makefile I had to add -mhard-float to the gcc line, otherwise the linker would complain. It might not hurt to do so even if your ARM toolchain is configured for hardware FP by default.
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby spideyfly » Sat Jun 09, 2007 12:42 am

Hey CoBB, I'm curious about your Hume project. Did you get it running?
spideyfly
New User
 
Posts: 18
Joined: Sat May 26, 2007 10:15 am

Postby CoBB » Thu Jul 12, 2007 7:55 pm

Okay, the Hume engine seems to be pretty stable, and it supports every sensor I could get my hands on, which inlcudes the colour sensor (without RGB reading though) and the compass too. However, I have an issue with the ultrasonic sensor, and no matter how long I’m looking at the source, I can’t seem to figure it out.

My problem is that as soon as the closest object is too far for the sensor to detect (that would be after around 2.2 metres), it simply keeps returning the last valid reading. And it’s i2c_start_transaction() that gives me this value again (on top of it, as a result of a successful transaction), since as you can see I overwrite the reading with -1 as soon as I use it (copy it to *val). So how can I detect this condition?

Code: Select all
boolean read_peripheral(uint16 id, uint8 size, int32 *val) {
  static U8 i2cp_busy[4] = {0, 0, 0, 0};
  static U16 i2cp_value[4] = {0, 0, 0, 0};
  static S32 motor_cnt[4] = {0, 0, 0, 0};
  /* I2C defaults */
  U8 reg = 0x42, len = 1;

  switch (getId(id)) {
  case NxtButton:
    /* Bits: 0 - enter, 1 - left, 2 - right, 3 - escape */
    *val = buttons_get();
    break;
  case NxtEnterButton:
    *val = 0 != (buttons_get() & 0x01);
    break;
  case NxtEscapeButton:
    *val = 0 != (buttons_get() & 0x08);
    break;
  case NxtLeftButton:
    *val = 0 != (buttons_get() & 0x02);
    break;
  case NxtRightButton:
    *val = 0 != (buttons_get() & 0x04);
    break;

  case NxtCompassSensor:
    len = 2;
  case NxtColourSensor:
  case NxtUltrasonicSensor:
    if (i2cp_busy[getPort(id)]) {
      /* There was a transaction going on, so let's see if it ended */
      if (i2c_busy(getPort(id))) {
        /* No, still waiting, so let's not block anyone else */
        return FALSE;
      } else {
        U16 tmp = i2cp_value[getPort(id)];
        switch (getId(id)) {
        case NxtUltrasonicSensor:
          *val = tmp == (U16)-1 ? 0 : tmp & 0xff;
          break;
        case NxtColourSensor:
          *val = tmp & 0xff;
          break;
        case NxtCompassSensor:
          *val = ((tmp & 0xff) << 1) + ((tmp >> 8) & 1);
          break;
        }
        i2cp_value[getPort(id)] = -1;
        i2cp_busy[getPort(id)] = 0;
      }
    } else {
      /* There's no data available, so let's start a transaction and return nothing */
      i2cp_value[getPort(id)] = -1;
      i2cp_busy[getPort(id)] =
        !i2c_start_transaction(getPort(id), 1, reg, len, (U8*)&i2cp_value[getPort(id)], len, 0);
      return FALSE;
    }
    break;

  case NxtLightSensor:
  case NxtSoundSensor:
    /* The raw readings are 'upside-down', so we reverse them */
    *val = sensor_adc(getPort(id)) ^ 0x03ff;
    break;
  case NxtTouchSensor:
    *val = sensor_adc(getPort(id)) < 600;
    break;

  case NxtMotorSpeed:
    *val = nxt_motor_get_count(getPort(id)) - motor_cnt[getPort(id)];
    motor_cnt[getPort(id)] = nxt_motor_get_count(getPort(id));
    break;

  case NxtMotorCount:
    *val = nxt_motor_get_count(getPort(id));
    break;

  default:
    /* Not implemented or unknown: nothing returned */
    return FALSE;
  }
  return TRUE;
}
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby lawrie » Sun Jul 15, 2007 3:54 pm

lejos NXJ does not get this effect - I wonder why.

This code was written by Charles Manning and has not been touched for 6 months or more. Charles had a lot of trouble with the Ultrasonic sensor, as is does not appear to implement I2C correctly. Other I2C sensors seem to be better behaved.

I am planning to look at the I2C code in the near future to see if I can make it work better for the Ultrasonic sensor, and make it do I2C writes.
lawrie
leJOS Team Member
 
Posts: 909
Joined: Mon Feb 05, 2007 1:27 pm

Postby CoBB » Tue Jul 17, 2007 9:48 am

Yes, it’s strange. I’m always trying to replicate what I see in the nxt classes, and this approach works with everything else. In any case, I’ll keep trying.

But what exactly should happen if the closest object is too far? Should I expect a failed transaction, a successful transaction that doesn’t write anything in the buffer or what? How much time does it take to receive data? I can’t really afford to block the whole program for the sake of a single peripheral...

Edit: I just read among the limitations that the sensor can only be read five times a second, and I look at it much more often. However, I just tested the sensor by itself, and a delay of five milliseconds seems to be perfectly enough. Besides, if I set too little delay, I don't get any data anyway, which is not the case here.

Edit 2: As it turns out, that was indeed the cause of the problem. My program was too fast. It wasn’t obvious, since the new values kept arriving, only the invalid distances were impossible to detect.
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby CoBB » Mon Jul 23, 2007 2:02 pm

While cleaning up the code, I noticed something strange: the uart functions are not referenced anywhere apart from the ISR table. Do they (or will they ever) serve any purpose?
User avatar
CoBB
Novice
 
Posts: 73
Joined: Tue Apr 24, 2007 12:24 pm

Postby lawrie » Mon Jul 23, 2007 5:16 pm

Charles Manning wrote the uart code but has not been active this year. I think he intended it to be used for Bluetooth and high-speed comms.

When I wrote the Bluetooth driver I used DMA in a similar way to the Lego code, so did not use the uart code. It might be used in the future, particularly if Charles becomes active again.
lawrie
leJOS Team Member
 
Posts: 909
Joined: Mon Feb 05, 2007 1:27 pm


Return to NXJ Projects

Who is online

Users browsing this forum: No registered users and 3 guests

more stuff